Partial class template argument deduction in C++17
Asked Answered
P

2

13

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?

Pasquale answered 19/8, 2019 at 20:33 Comment(2)
In the example given, you can specify T and have U and have V deduced, or specify T and U, and have V deduced. See the pattern? It would be nice to have named template parameters in C++, unfortunately we do not.Engagement
Related: c++ - C++17 class template partial deduction - Stack OverflowUrtication
N
11

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>
Nucleonics answered 19/8, 2019 at 21:0 Comment(0)
Z
15

CTAD (Class Template Argument Deduction) is an all or nothing process currently. You either specify nothing and allow the compiler to deduce all of the arguments, or you specify all of the arguments taking the compiler out of the loop.

There is a paper (P1021R0) which asks for this and more, but it has not yet been accepted. There was a paper asking for partial specialization but after revisions it has been removed. The newest revision still includes a proposal to have CTAD function when using an alias.


Per @Barry Support for Alias templates (P1814) and Aggregates (P1816) have been added to the working draft for C++20. No support for partial CTAD or CTAD with inherited constructors has been added.

Zerk answered 19/8, 2019 at 20:38 Comment(2)
The latest revision of the paper is P1021, which was split off into two different papers: P1814 for alias templates and P1816 for aggregates. Both have been added to the working draft for C++20. There will not be any partial CTAD, nor support for inherited constructors.Peneus
@Peneus Thanks for the sources. I'll add that in.Zerk
N
11

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>
Nucleonics answered 19/8, 2019 at 21:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.