Problem w GCC / C ++ 17 z klasą szablonów szablonów

10

Rozważ 2 następujące przeciążenia

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

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

Pierwszy działa dla klas regularnych, a drugi dla szablonów, które nie są tworzone. Na przykład:

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

Teraz rozważ następującą funkcję szablonu:

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

W GCC daje błąd przy niejednoznacznej rozdzielczości przeciążenia, podczas gdy Clang kompiluje. Co ciekawe, drugie wywołanie test () nie powoduje błędów (nawet w GCC). Co więcej, jeśli template<typename U>usunę coś na templfun, gcc przestanie narzekać.

Czy to błąd w GCC, czy to nielegalny kod?

Marieddu
źródło

Odpowiedzi:

4

GCC się myli; struct Ajest szablonową jednostką, ale wyraźnie nie jest szablonem (ponieważ nie zaczyna się od templatesłowa kluczowego), więc nie ma dwuznaczności.

Aby to potwierdzić, możemy zmienić nazwę parametru type, aby zobaczyć, że G ++ próbuje użyć przeciążenia szablonu-szablonu.

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>();
}

Wyjście G ++: ( link do 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() {
      |      ^~~~

Najwyraźniej „ candidate: 'bool test() [with Y = templfun()::A]'” jest fałszywy.

Zauważ, że typy lokalne nie były dozwolone jako argumenty szablonów przed C ++ 11 (patrz C ++ 03 § 14.3.1.2), co mogłoby wyjaśnić złożoność implementacji G ++.

rustyx
źródło