2014-12-19 12 views
14

Il seguente codice viene compilato con GCC 4.9.2 ma non con Clang 3.5.0:Gli operatori di conversione espliciti sono consentiti negli elenchi di inizializzazione rinforzati?

#include <string> 

class Foo 
{ 
public: 
    explicit operator std::string() const; 
}; 

std::string bar{Foo{}}; // Works in g++, fails in clang++ 
std::string baz(Foo{}); // Works in both 

clang ++ dice:

foo.cpp:9:13: error: no matching constructor for initialization of 'std::string' 
     (aka 'basic_string<char>') 
std::string bar{Foo{}}; 
      ^~~~~~~~ 
...: note: candidate constructor not viable: no known conversion from 'Foo' to 
     'const std::basic_string<char> &' for 1st argument 
     basic_string(const basic_string& __str); 
    ^

Curiosamente, se funziona std::string è sostituito con un tipo primitivo come int .

+1

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51553 e il clangore legata non bug sono probabilmente rilevanti –

risposta

4

Questo sembra essere un bug Clang. [Over.match.list]/1:

Quando gli oggetti di tipo non-aggregato classe T sono elenco inizializzata (8.5.4), la risoluzione di sovraccarico seleziona il costruttore in due fasi:

  • [..]
  • Se non viene trovato nessun costruttore di inizializzazione-list praticabile, risoluzione sovraccarico viene eseguito di nuovo, dove le funzioni candidati sono tutti i costruttori della classe T e l'elenco di argomenti costituito da elementi della lista di inizializzazione.

Dalla seconda linea compila bene, c'è una contraddizione: Essi dovrebbero essere equivalenti quando si tratta di sovraccaricare risoluzione.

+0

corretta, dare un'occhiata a http://stackoverflow.com/q/32144976/1938163 –

3

Da [class.conv.fct]/2:

Una funzione di conversione può essere esplicito (7.1.2), nel qual caso è considerato solo come conversione definita dall'utente per inizializzazione diretta (8.5).

Quindi la domanda è come inizializzare i tuoi oggetti. Chiaramente, baz è inizializzato direttamente, quindi funziona. Al contrario, bar è inizializzato in elenco diretto, ma non è inizializzato direttamente, pertanto la conversione esplicita non è disponibile.

+3

Penso che non funzioni in Clang anche con una funzione di conversione non esplicita –

+0

@PiotrS. Wow hai ragione, è pazzesco. Questo è sicuramente un bug Clang giusto? –

+0

@TavianBarnes Non lo so, sono curioso anch'io –

2

clang non sembra preoccuparsi se l'operatore di conversione è explicit o no, e credo che sia corretto a causa della formulazione [over.best.ics].

Innanzitutto, il diretto inizializzazione

std::string baz(Foo{}); 

lavora sia gcc e clang, e si spiega con [class.conv.fct]/2 come menzionato in KerrekSB's answer.

Il diretta-list-inizializzazione

std::string bar{Foo{}}; 

invece, non considera conversioni qualsiasi definiti dall'utente, explicit o meno.

Citando N3337, §13.3.3.1/4[over.best.ics]

Tuttavia, quando si considera l'argomento di un costruttore o funzione di conversione definita dall'utente che è un candidato da 13.3.1.3 quando invocato per la copia/lo spostamento del temporaneo nella seconda fase di una inizializzazione della copia di classe, da 13.3.1.7 quando si passa l'elenco di inizializzazione come un singolo argomento o quando l'elenco di inizializzazione ha esattamente un elemento e una conversione in qualche classe X o un riferimento a (possibilmente cv-qualif ied) X è considerato per il primo parametro di un costruttore di X o 13.3.1.4, 13.3.1.5 o 13.3.1.6 in tutti i casi, solo le sequenze di conversione standard e le sequenze di conversione ellissi sono considerate.

+0

E 'possibile che la sezione parli specificamente degli elenchi di inizializzatori (ad esempio 'std :: initializer_list'), e non di elenchi di init forzati in generale? –

+0

E suppongo che se hai ragione allora clang è sbagliato ad accettare il codice quando 'std :: string' viene sostituito con' int'? –

+0

@Tavian No, sono abbastanza sicuro che si tratti di bretelle-init-list perché il 13.3.1.7 menzionato qui copre l'inizializzazione dell'elenco in generale. E non conosco la risposta alla tua seconda domanda. Il paragrafo citato menziona 'classe X' dappertutto, quindi forse questo si applica solo ai tipi definiti dall'utente? Dovresti aggiungere l'osservazione 'int' al tuo bug bug clang per ottenere una risposta ad entrambi. – Praetorian

Problemi correlati