Vahagn
Vahagn

Reputation: 4850

Bug in gcc with const& template parameters?

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

Answers (1)

Barry
Barry

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

Related Questions