2015-10-15 22 views
24

Mam następujący kod, który kompiluje się pod g ++, ale nie z clang.Czy to jest prawidłowy C++ 11

Clang skompiluje kod, jeśli zostanie zmieniony na różne drobne sposoby, na przykład scalenie 2 deklaracji przestrzeni nazw.

// The problem disappears without namespaces. 
namespace Root { 
    // The problem disappears if 'g' is in the global namespace, and we change 
    // the friend declaration to '::g' 

    // The problem disappears if 'g' has void return type. 

    // The problem disappears if we get rid of the 'Value' template argument 
    // and the 'value' parameter. 
    template<typename Value, typename Defaulted = void> 
    bool g(Value value); 

    // The problem disappears if MyClass is not a template. 
    template<typename ClassValue> 
    class MyClass { 
    private: 
     template<typename Value, typename Defaulted> 
     friend bool g(Value value); 
    }; 
} 

// The problem disappears if we declare the Root namespace in a single block 
// containing 'g', 'MyClass' and 'f'. 

// The problem remains if we declare f in the global namespace and reference 
// Root::g. 
namespace Root { 
    void f() { 
     MyClass<int> value; 

     g(value); 
    } 
} 

Kompilacja z brzękiem:

clang -fsyntax-only -std=c++11 testcase.cpp 

Aby podczas kompilacji g ++

g++ -fsyntax-only -std=c++11 testcase.cpp 

są wersje g ++ 4.9.2, 3.6.0 szczęk, zarówno w rdzeniu Ubuntu 15,04.

Clang daje komunikat o błędzie:

testcase.cpp:24:9: error: no matching function for call to 'g' 
     g(value); 
     ^
testcase.cpp:14:21: note: candidate template ignored: couldn't infer template argument 'Defaulted' 
     friend bool g(Value value); 
       ^
1 error generated. 
+0

Funkcja przyjaciel (nawet jeśli zadeklarowana w klasie) ma zakres przestrzeni nazw. Tak więc w tym przypadku masz 2 deklaracje funkcji dla 'bool Root :: g()'. Parametry szablonu nie zmieniają deklaracji. Właśnie dlatego twoje drobne zmiany sprawiają, że ten kod działa. Jestem bardziej zaskoczony, że kompiluje się z g ++. –

+3

@SimonKraemer Możesz zadeklarować funkcje wiele razy. A deklaracja "przyjaciela" i tak nie odtworzy tej funkcji. – Barry

+0

Czy to Twój pełny kod, czy tylko odpowiednia część? –

Odpowiedz

7

Wierzę, że to jest błąd, dzyń. Od [temp.param], mamy:

Jeżeli deklaracja szablon funkcja przyjaciel określa domyślny Template-argumentu, że deklaracja powinna być definicja i będzie tylko deklaracja szablonu funkcji w jednostka tłumaczeniowa.

Zestaw domyślnych Template-argumentów dostępnych do użytku uzyskuje się poprzez połączenie domyślne argumenty z wszystkie wcześniejsze deklaracje szablonu w argumentach sama domyślny sposób funkcyjnych są (8.3.6).

Ten ostatni punkt oznacza, że ​​możemy napisać:

template <typename T, typename U=int> 
void h(); 

template <typename T, typename U> 
void h() { } 

h<int>(); 

I to jest kod, który doskonale Clang kompiluje utworzone. Mamy nie można określić domyślny szablon-argument g oparciu o reguły cytowany jako g uprzednio zadeklarowana, ale nie określając go nadal powinien zachować Defaulted dostępne do wykorzystania jako void poprzez etap scalania. Jeśli argument domyślny jest dostępny, wówczas wyszukiwanie powinno być w stanie znaleźć wymagane przez nas g.

Rozwiązaniem byłoby po prostu przyjaciela specjalizacja dbamy o:

friend bool g<>(MyClass value); 
+0

Odliczanie do @ T.C. poprawiając mnie w 5 ... 4 ... – Barry

+0

Dzięki - zgadzam się z tym, co mówisz o połączeniu, i to ma dla mnie sens. Ale myślałem, że nie wolno ci określać, do czego domyślnie przyjmuje szablon w domyślnym poleceniu. Biorąc to pod uwagę, moja (błędna) interpretacja pierwszego akapitu byłaby następująca: Zgłaszając przyjaciela z szablonem, który już ma wartość domyślną (zadeklarowaną gdzie indziej), muszę podać treść funkcji wraz z deklaracją przyjaciela? –

+0

Po więcej myśli, rozumiem teraz. Możesz określić wartości domyślne na szablonie znajomego, którego nie zdawałem sobie sprawy, i to mnie zdezorientowało. Wygląda to bardzo podobnie do klangowego błędu. –

Powiązane problemy