c++templatesc++17

Deduce member template type from class template, different types


I have the following classes. I would like to have "class First" with a template, and depending on it's type, set the type for "class Second", like the following.

template<typename T>
class Second
{
public:
    T Get(T t)
    {
        return t;
    }
};

template<typename T>
class First
{
public:
    // if T=double --> vector<double>, if T=string --> long
    Second<"auto deduce"> second; 

};

int main()
{
    First<int> first; // compile error, not in list
    auto val = first.second.Get(1);

}

I can get it to work like this, but would rather avoid the following:

#include <iostream>
#include <vector>
#include <string>

template<typename T>
class Second
{
public:
    T Get(T t)
    {
        return t;
    }
};

template<typename T, typename U>
class First
{
public:
    Second<U> second;

};

int main()
{
    First<double, std::vector<double>> a;

    First<std::string, long> b;
}

Been trying to get something to work with constexpr. I believe I could use std::conditional_t, but it doesn't look clean since std:: conditional will require nesting itself in the template call.


Solution

  • Mapping ("auto-deduce") can be done simply with template specialization:

    #include <string>
    #include <vector>
    
    // --------------------------------
    // "Auto deduce"
    // --------------------------------
    template<typename T>
    struct deduce;
    
    template<>
    struct deduce<double>
    {
        using type = std::vector<double>;
    };
    
    template<>
    struct deduce<std::string>
    {
        using type = long;
    };
    
    template<typename T>
    using deduce_t = typename deduce<T>::type;
    
    // --------------------------------
    // Your code
    // --------------------------------
    
    template<typename T>
    class Second
    {
    public:
        T Get(T t)
        {
            return t;
        }
    };
    
    template<typename T>
    class First
    {
    public:
        Second<deduce_t<T>> second;
    
    };
    
    int main()
    {
        // First<int> first; // This would fail to compile
    
        First<double> first;
        auto val = first.second.Get({1});
        static_assert(std::is_same<decltype(val), std::vector<double>>::value, "");
    }