Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can template argument deduction for class templates work for non type template parameters?

Can classes like the following take advantage of template argument deduction for class templates?

template <int I>
struct Number
{
    /* appropriate constructor here */
}; 

By "take advantage" I mean, is there a way to have (implicitly or explicitly) the value of I deduced? An example use would be the following:

Number a(3); // a's type is Number<3>
like image 265
Lorah Attkins Avatar asked Mar 01 '17 23:03

Lorah Attkins


2 Answers

Template argument deduction for class templates can deduce non-type template parameters, but not in the way you're trying to do it.

For example

template <std::size_t size>
struct ArrayWrapper {
    ArrayWrapper(std::array<int, size> a);
};
int main() {
    std:array<int, 5> a;
    ArrayWrapper aw(a);  // ok; declares ArrayWrapper<5>
}

But in your example you are trying to have a non-type template parameter deduced from the value of an argument. In general, the template deduction system of C++ does not support that, whether for class templates or in any other context.

like image 174
Brian Bi Avatar answered Oct 19 '22 10:10

Brian Bi


Template deduction for constructors is still deduction - and deduction is all about types. The only way you can deduce a value is if that value is a non-type template argument of one of the types being deduced. So we can simply lift the 3 from a boring old int to a sophisticated, modern std::integral_constant<int, 3>:

template <int I> using int_t = std::integral_constant<int, I>;
template <int I> constexpr int_t<I> int_c;

template <int I>
struct Number {
    Number(int_t<I> ) { }
};

int main()
{
    Number n(int_c<3> );
}

Worth noting that the point of this feature is to avoid having to duplicate writing types (such as with std::lock_guard), or cases where naming the types may be impossible (such as class template specializations constructed with a lambda). Neither of those really apply here. When you have a value - that's it, just use the value:

Number<3> n;

That's the same number of characters as Number n{3}, which doesn't work, so there's nothing to gain.

like image 22
Barry Avatar answered Oct 19 '22 10:10

Barry