2015-10-15 22 views
24

Ho il seguente codice che compila sotto g ++, ma non con clang.È valido C++ 11

Clang compilerà il codice se modificato in vari modi minori, come l'unione delle 2 dichiarazioni di namespace.

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

Per compilare con clang:

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

Per compilare con g ++:

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

versioni sono g ++ 4.9.2, clang 3.6.0, sia sul nucleo Ubuntu 15.04.

Clang dà il messaggio di errore:

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

La funzione amico (anche se ha dichiarato in una classe) ha un ambito spazio dei nomi. Quindi in questo caso hai 2 dichiarazioni di funzione per 'bool Root :: g()'. I parametri del modello non cambiano la dichiarazione. Ecco perché le tue piccole modifiche rendono questo codice funzionante. Sono davvero più sorpreso che questo compili con g ++. –

+3

@SimonKraemer È possibile dichiarare funzioni più volte. E la dichiarazione "amico" non dichiarerebbe comunque la funzione. – Barry

+0

È questo il tuo codice completo o solo la parte rilevante? –

risposta

7

Credo che questo sia un bug clang. Da [temp.param], abbiamo:

Se una dichiarazione di amico modello di funzione specifica un default modello-argomentazione, tale dichiarazione deve essere una definizione e sarà l'unica dichiarazione del modello funzione l'unità di traduzione.

L'insieme di predefiniti template-argomenti disponibili per l'uso è ottenuta fondendo i parametri predefiniti da tutte le dichiarazioni precedenti del modello in argomenti stesso modo della funzione predefinita sono (8.3.6).

Quest'ultimo punto significa che possiamo scrivere:

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

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

h<int>(); 

E questo è perfettamente formata codice che Clang compilazioni. Non Noi in grado di specificare il modello-argomento di default per g basato sullo stato citato, come g è dichiarato in precedenza, ma non specificando che dovrebbe ancora mantenere Defaulted disponibili per l'uso come void attraverso il passo di unione. Se l'argomento predefinito è disponibile, la ricerca dovrebbe essere in grado di trovare lo g che vogliamo.

Una soluzione potrebbe essere quella di semplice amico specializzazione ci sta a cuore:

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

Conto alla rovescia per @ T.C. correggendomi in 5 ... 4 ... – Barry

+0

Grazie - Sono d'accordo con quello che stai dicendo sulla fusione, e questo ha senso per me. Ma pensavo che non ti fosse permesso di specificare in quale modo un parametro del modello si posizionasse automaticamente in un decl di un amico. Detto questo, la mia (errata) interpretazione del primo paragrafo sarebbe quindi: dichiarando un amico con un parametro template che ha già un valore predefinito (dichiarato altrove), devo fornire il corpo della funzione insieme alla dichiarazione amico? –

+0

Dopo aver riflettuto, capisco ora. Puoi specificare i valori predefiniti su un modello amico, cosa che non avevo realizzato e che mi ha confuso. Quindi questo sembra molto simile a un bug clang. –