Проблема в GCC / C ++ 17 с шаблоном шаблона класса - PullRequest
10 голосов
/ 18 февраля 2020

Рассмотрим 2 следующие перегрузки

template<typename T>
bool test() {
    return true;
}

template<template<typename ...> class T>
bool test() {
    return false;
}

Первый работает для обычных классов, второй - для шаблонов, которые не создаются. Например:

    std::cout<<test<int>()<<std::endl; <-- this yields 1
    std::cout<<test<std::list>()<<std::endl; <--this yields 0

Теперь рассмотрим следующую шаблонную функцию:

template<typename U>
bool templfun(){
    struct A{
        bool f(){
            return test<A>(); // <-- this gives an error
        }
    };
    return test<A>();  // <-- this is ok
}

В G CC выдает ошибку для неоднозначного разрешения перегрузки, пока Clang компилируется. Интересно, что второй вызов test () не приводит к ошибкам (даже в G CC). Более того, если я уберу вещь template<typename U> поверх templfun, g cc перестанет жаловаться.

Это ошибка с G CC или это недопустимый код?

1 Ответ

4 голосов
/ 18 февраля 2020

G CC неправильно; struct A является шаблонной сущностью , но явно не является шаблоном (так как оно не начинается с ключевого слова template), поэтому нет никакой двусмысленности.

Чтобы подтвердить, мы можем переименовать параметр типа, чтобы увидеть, что G ++ пытается использовать перегрузку шаблона-шаблона.

template <typename X>
bool test() {
    return true;
}

template <template <typename...> class Y>
bool test() {
    return false;
}

template <typename U>
bool templfun() {
    struct A {
        bool f() {
            return test<A>(); // <-- this gives an error
        }
    };
    return test<A>(); // <-- this is ok
}

bool run() {
    return templfun<int>();
}

Вывод G ++: ( ссылка на godbolt )

<source>:15:27: error: call of overloaded 'test<templfun() [with U = int]::A>()' is ambiguous
   15 |             return test<A>(); // <-- this gives an error
      |                    ~~~~~~~^~

<source>:2:6: note: candidate: 'bool test() [with X = templfun() [with U = int]::A]'
    2 | bool test() {
      |      ^~~~

<source>:7:6: note: candidate: 'bool test() [with Y = templfun()::A]'
    7 | bool test() {
      |      ^~~~

Очевидно, что "candidate: 'bool test() [with Y = templfun()::A]'" является поддельным.

Обратите внимание, что локальные типы не были разрешены в качестве аргументов шаблона до C ++ 11 (см. C ++ 03 § 14.3.1.2), чтобы можно было объяснить сложность реализации G ++.

...