Search code examples
c++default-template-argument

multiple default template argument cases that depend on a template argument respectively


I would like to define two particular default cases for a template class A.

Is something similar possible?:

template<typename T1, typename T2>
class A{
    // ...
};

struct X;
// if necessary, I can also define X right here.

template<>
A<X> = A<X,int>;

template<typename T>
A<T> = A<T,T>;

int main(){
    A<X> a;     // shall construct an instance of A<X,int>
    A<float> b; // shall construct an instance of A<float,float>
}

I see how it can be done by using a derived of A. However, I would hope that it is also possible in a similarly straight-forward way to the one presented in the non-functioning snippet above.


Solution

  • You can use template specialization to help you deduce the type of your second argument (this can easily be extended to other specializations too):

    #include <type_traits>
    
    namespace details
    {
        // in allmost all cases we want to imply type int for the second argument
        template<typename type_t>
        struct deduced_second_arg_t_helper
        {
            using type = int;
        };
    
        // except for float, so use a template specialization to deduce a float
        template<>
        struct deduced_second_arg_t_helper<float>
        {
            using type = float;
        };
    
        // shorthand like 
        template<typename type_t>
        using deduced_second_arg_t = typename deduced_second_arg_t_helper<type_t>::type;
    }
    
    // now the second argument can be deduced from the first
    template<typename type_t, typename second_arg_t = details::deduced_second_arg_t<type_t>>
    struct A
    {
        second_arg_t some_value;
    };
    
    // or simplified, we use the deduced type internally
    template<typename type_t>
    struct B
    {
        using some_value_t = details::deduced_second_arg_t<type_t>;
        some_value_t some_value;
    };
    
    struct X
    {
    };
    
    int main()
    {
        A<X> a_x;
        A<float> a_f;
        static_assert(std::is_same_v<decltype(a_x.some_value), int>);
        static_assert(std::is_same_v<decltype(a_f.some_value), float>);
    
        B<X> b_x;
        B<float> b_f;
        static_assert(std::is_same_v<decltype(b_x.some_value), int>);
        static_assert(std::is_same_v<decltype(b_f.some_value), float>);
    
        return 0;
    }