Ошибка в gcc с параметрами const& template?
Рассмотрим этот код:
#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, и вот живой пример. Вопрос в том, если это ошибка компилятора или я что-то не так делаю?
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
}
И похоже на исходный пример: вам понадобится одна специализация для значений и одна специализация для ссылок. Ссылка в нетиповом параметре template-template для C
может не быть необходимым.