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

c++, c++11, templates

Solution

It would be easy to make just this bit work, but then people would complain about how using struct template parameters does not work in all the same situations the other template parameters do (consider partial specializations, or what to do with `operator==`).

In my opinion, it's too messy to get the whole cake, and getting just one tiny slice isn't satisfying enough, and possibly more frustrating. Making just this tiny bit work won't give me more power than something like the following, which has the additional advantage of working with all kinds of stuff (including partial specializations) out of the box.

template <int X, int Y, int Z>
struct meta_triple {
    // static value getters
    static constexpr auto x = X;
    static constexpr auto y = Y;
    static constexpr auto z = Z;
    // implicit conversion to Triple 
    constexpr operator Triple() const { return { X, Y, Z }; }
    // function call operator so one can force the conversion to Triple with
    // meta_triple<1,2,3>()()
    constexpr Triple operator()() const { return *this; }
};

Problem

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 `int`s, 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.

Original source

Related problems