2017-02-09 13 views
3

this Рассмотрим код:Ошибка в gcc с параметрами const и шаблона?

#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!? 

Я использую GCC-7.0.1 и here является живым примером. Вопрос в том, является ли это ошибкой компилятора, или я делаю что-то неправильно?

+0

Только мое предположение: простой 'auto' (из' NonTypes') не может вывести ссылочный тип, который бы соответствовал 'const int &' того, что выводилось в 'Class' (по крайней мере, оно работает с' const auto & NonTypes') –

+0

@PiotrSkotnicki Не было бы тогда смысл, что он будет работать с 'decltype (auto)'? – user975989

+0

@ user975989 Я думаю, что соответствие шаблона специализации сводится к выведению типов созданного шаблона функции, где 'decltype (auto)' бесполезно –

ответ

1

Давайте упрощения примера немного:

template <template <auto> class C, auto N> 
void foo(C<N>) { } 

int main() { 
    foo(II<TEN>{}); // ok 
    foo(RR<REF>{}); // error 
} 

Проблема заключается в том, что нормальные auto правила вычет применяется для N, который получает выведенной в REF случае типа int. Существует несоответствие между типом шаблона типа не-типа - int const& - и аргументом - int, поэтому он плохо сформирован.

Если мы перевернули пример взять auto const& N (или auto&& N) вместо этого, то он был бы II<TEN> вызова, который будет плохо сформирован по той же причине - мы бы теперь получить шаблон аргумент ссылочного типа но параметр является не ссылочным типом.

Вы не можете обрабатывать оба случая с одной функцией на современном языке. Вам понадобится два:

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 
} 

И аналогично вашему первоначальному примеру: вам нужна одна специализация для значений и одна специализация для ссылок. Ссылка в параметре шаблона шаблона-шаблона для C может не понадобиться.