c++c++17template-argument-deductionclass-templatectad

Partial class template argument deduction in C++17


In the example below, we use the C++17 feature "Class template argument deduction" to deduce that val is of type Base<int, double, bool>:

template<class T, class U, class V>
struct Base {
    Base(T, U) { };
    Base(T, U, V) { };
    Base(V) { };
};

void func() {
    Base val(1, 4., false);
}

Now, is it possible to partially specify the template arguments, and let the remaining ones be deduced? Effectively something like this:

Base<V = bool> val1(1, 4.);        // U & V deduced --> Base<int, double, bool>
Base<T = bool, T = int> val2(5.);  // V deduced     --> Base<bool, int, double>

I've tried e.g.

template<class T, class U> using Base2 = Base<T, U, double>;

void func() {
    NewBase2 val(1, 2);
}

but it doesn't compile: 'Base2': use of alias template requires template argument list.

Is partial deduction possible somehow? If it is not possible directly, are there any good workarounds?


Solution

  • You might add deduction guide as follow:

    template<class T, class U>
    Base(T, U) -> Base<T, U, bool>;
    
    template<class V>
    Base(V) -> Base<bool, int, V>;
    

    which allows

    Base val1(1, 4.); // Base<int, double, bool>
    Base val2(5.);    // Base<bool, int, double>
    

    If you want to specify the "default" template, you might use the old way with make_

    template <typename V, typename T, typename U>
    Base<T, U, V> make_Base(T t, U u)
    {
        return Base<T, U, V>{t, u};
    }
    
    template <typename T, typename U, typename V>
    Base<T, U, V> make_Base(V v)
    {
        return Base<T, U, V>{v};
    }
    
    
    auto val1 = make_Base<bool>(1, 4.);   // Base<int, double, bool>
    auto val2 = make_Base<bool, int>(5.); // Base<bool, int, double>