Ошибка в 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 может не быть необходимым.

Другие вопросы по тегам