Reputation: 4850
Consider this code:
#include <type_traits>
template < int > struct II { };
template < const int& > struct RR { };
template < template <auto> typename Class, typename Type > struct Check : std::false_type { };
template < template <auto> typename Class, auto NonTypes > struct Check<Class,Class<NonTypes>> : std::true_type { };
constexpr int TEN = 10;
constexpr const int& REF = TEN;
static_assert(Check<II,II<TEN>>::value); // passes
static_assert(Check<RR,RR<REF>>::value); // FAILS!?
I am using gcc-7.0.1 and here is the live example. The question is if this is a compiler bug or I am doing something wrong?
Upvotes: 3
Views: 166
Reputation: 303487
Let's simplify the example a bit:
template <template <auto> class C, auto N>
void foo(C<N> ) { }
int main() {
foo(II<TEN>{} ); // ok
foo(RR<REF>{} ); // error
}
The problem is that the normal auto
deduction rules apply for N
, which gets deduced in the REF
case to type int
. There's a mismatch between the non-type template parameter type - int const&
- and the argument - int
, so it's ill-formed.
If we flipped the example to take auto const& N
(or auto&& N
) instead, then it'd be the II<TEN>
call that would be ill-formed for the same reason - we'd now get a template argument of reference type but the parameter is a non-reference type.
You can't handle both cases with one function in the language today. You'd need two:
template <template <auto> class C, auto N> void foo(C<N> ) { } // #1
template <template <auto&&> class C, auto&& N> void foo(C<N> ) { } // #2
int main() {
foo(II<TEN>{} ); // ok: calls #1
foo(RR<REF>{} ); // ok: calls #2
}
And similar for your original example: you'd need one specialization for values and one specialization for references. The reference in the template-template non-type parameter for C
may not be necessary.
Upvotes: 1