2017-05-16 9 views
40

Zmarnowałem niezliczoną ilość godzin, aby zidentyfikować problem z gcc. Chciałem przetestować naszą bazę kodu za pomocą innego kompilatora, aby znaleźć więcej ostrzeżeń, które mogły zostać utracone przez Clang. Byłem zszokowany, że praktycznie połowa projektu przestała się kompilować z powodu niepowodzenia odrzucenia szablonu. Tutaj starałem się oswoić moją sprawę z najprostszym kodem.Wszystkie wersje GCC walczą z szablonem, który ma domyślny typ w definicji

#include <type_traits> 

struct Foo 
{ }; 

// This is a template function declaration, where second template argument declared without a default 
template <typename T, typename> 
void foo(const Foo & foo, T t); 

// This is a template function definition; second template argument now has a default declared 
template <typename T, typename = typename std::enable_if<1>::type> 
void foo(const Foo & foo, T t) 
{ 
} 

int main(int argc, char ** argv) 
{ 
    foo(Foo{}, 1); 
    return 0; 
} 

ignorować 1 w std::enable_if<1>. Oczywiście jest to stała wartość tylko po to, aby nie komplikować rzeczy, kiedy to nie ma znaczenia.

Ten fragment kodu zestawia [1] z szczęk (3,4 za pomocą 4,0) ICC (16, 17), Visual C++ (19.00.23506). Zasadniczo nie mogłem znaleźć żadnego innego kompilatora C++ 11, który, z wyjątkiem gcc (4.8 do 7.1), nie kompiluje tego fragmentu kodu.

Pytanie brzmi, kto ma rację, a kto się myli? Czy gcc zachowuje się zgodnie ze standardem?

Oczywiście nie jest to krytyczny problem. Mogę łatwo przenieść std::enable_if do deklaracji. Jedyną ofiarą byłaby estetyka. Ale miło jest móc ukryć brzydki 100-literowy kod, który nie jest natychmiastowy dla użytkownika funkcji bibliotecznej w implementacji.


Przykład na żywo pod numerem godbolt.org.

+2

Na stronie en.cppreference.com mówi o [domyślne argumenty szablonu] (http://en.cppreference.com/w/cpp/language/template_parameters#Default_template_arguments) »Domyślne argumenty szablonu, które pojawiają się w deklaracjach i definicji są połączone podobnie jak domyślne argumenty funkcji «. Dla [domyślne argumenty funkcji] (http://en.cppreference.com/w/cpp/language/default_arguments) znalazłem »... wskazane przez użycie następującej składni dla parametru na liście parametrów deklaracji funkcji« . Jeśli poprawnie to zinterpretuję, to * masz *, aby mieć domyślny argument w deklaracji. –

+0

@HenriMenke, działa dla funkcji w ** gcc **: https://godbolt.org/g/kXNbYi. Wydaje się, że ** gcc ** ma podwójne standardy dla funkcji i szablonów ... – GreenScape

+0

@HenriMenke Zobacz przykład "szablonu <...> klasa A" na 14.1/10. Działa tak jak w g ++, ale nie w przypadku zastąpienia klasy przez funkcję. –

Odpowiedz

34

Co mówi średnia ([1] strona 350):

Zestaw domyślnych szablonach argumentów dostępnych do użytku wraz z deklaracją szablon lub definicji uzyskuje się poprzez połączenie Wartość domyślna argumenty z definicji (jeśli w zakresie) i wszystkie deklaracje w zakresie zakres w ten sam sposób domyślne argumenty funkcji są (8.3.6). [ przykład:

template<class T1, class T2 = int> class A; 
template<class T1 = int, class T2> class A; 
is equivalent to 
template<class T1 = int, class T2 = int> class A; 

- przykład end]

Tak GCC jest źle tutaj. Ignoruje domyślne argumenty szablonu w deklaracjach.

Nie wszystkie deklaracje, tylko deklaracje szablonu funkcji. Deklaracje szablon klasy są w porządku:

#include <type_traits> 

template <typename T, typename> 
struct Foo; 

template <typename T, typename = typename std::enable_if<1>::type> 
struct Foo 
{ 
    T t; 
}; 

int main() 
{ 
    Foo<int> foo; 
    return 0; 
} 

żywo przykład na godbolt.org


Prawdopodobnie wynika to z charakteru jak non-default argumenty są wywnioskować. W szablonie funkcji są one odejmowane od argumentów funkcji. W szablonie klasy musimy je wyraźnie określić.

W każdym razie utworzyłem bug report.

+1

Domyślne argumenty szablonu dla szablonów funkcji są stosunkowo nowe (C++ 11). Nic dziwnego, że ludzie z GCC go nie zauważyli. –

Powiązane problemy