Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a struct be passed as value as template non-type parameter?

Non-type template parameters are obviously ones that aren't types, for example:

template<int x>
void foo() { cout << x; }

There are other options than int in that case, and I'd like to refer to this great answer.

Now, there's one thing that bugs me: structs. Consider:

struct Triple { int x, y, z; };

Triple t { 1, 2, 3 };

template<Triple const& t>
class Foo { };

Now, using normal nontype reference semantics, we can write:

Foo<t> f;

What's worth noting here is that t can't be constexpr or even const, because that implies internal linkage, which basically means that the line won't compile. We can bypass that by declaring t as const extern. That itself might be a bit weird, but the one that really made me wonder was why this isn't possible:

Foo<Triple { 1, 2, 3 }> f;

We get a really decent error from compiler:

error: Triple{1, 2, 3} is not a valid template argument for type const Triple& because it is not an lvalue.

We can't specify Triple in template by value, because that's disallowed. However, I fail to understand the real problem with that small line of code. What's the reasoning behind not allowing using structs as value parameters. If I can use three ints, why not a struct of three ints? If it has only trivial special members, it shouldn't be really different in handling than just three variables.

like image 532
Bartek Banachewicz Avatar asked Apr 09 '13 08:04

Bartek Banachewicz


People also ask

Which parameter is allowed for non-type template?

Which parameter is legal for non-type template? Explanation: The following are legal for non-type template parameters:integral or enumeration type, Pointer to object or pointer to function, Reference to object or reference to function, Pointer to member.

Can a struct be a template?

The entities of variable, function, struct, and class can have templates, which involve declaration and definition. Creating a template also involves specialization, which is when a generic type takes an actual type. The declaration and the definition of a template must both be in one translation unit.

Can we use non-type parameters as argument templates?

A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.


1 Answers

Updated answer for c++20 users:

C++20 adds support for class literal (class with constexpr constructor) non-type template parameters, which would allow the example in the original question to work, provided the template parameter is accepted by value:

template<Triple t> // Note: accepts t by value
class Foo { };

// Works with unnamed instantiation of Triple.
Foo<Triple { 1, 2, 3 }> f1 {};

// Also works if provided from a constexpr variable.
constexpr Triple t { 1, 2, 3 };
Foo<t> f2 {};

Further, all template parameter instances of Triple { 1, 2, 3 } throughout the program will refer to the same static storage duration object:

template<Triple t1, Triple t2>
void Func() {
    assert(&t1 == &t2); // Passes.
}

constexpr Triple t { 1, 2, 3 };

int main()
{
    Func<t, Triple {1, 2, 3}>();
}

From cppreference:

An identifier that names a non-type template parameter of class type T denotes a static storage duration object of type const T, called a template parameter object, whose value is that of the corresponding template argument after it has been converted to the type of the template parameter. All such template parameters in the program of the same type with the same value denote the same template parameter object.

Note that there are quite a few restrictions on the class literal types allowable by template parameters. For more detail, checkout this blog post I wrote explaining the usage and restrictions of literal class NTTPs: Literal Classes as Non-type Template Parameters in C++20.

like image 60
Kevin Hartman Avatar answered Oct 06 '22 22:10

Kevin Hartman