2014-12-19 12 views
14

Poniższy kod kompiluje z GCC 4.9.2, ale nie z Clang 3.5.0:Czy jawne operatory konwersji są dozwolone na listach inicjalizujących ze wzmocnionymi liniami?

#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 

brzękiem ++ mówi:

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); 
    ^

Co ciekawe, to działa, jeśli std::string otrzymuje z prymitywnego typu jak int .

+1

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51553 i związane dzyń non-bug są prawdopodobnie istotne –

Odpowiedz

4

To wydaje się być błąd Clang. [Over.match.list]/1:

gdy przedmioty nie zagregowanym klasy typu T to lista zainicjowany (8.5.4), rozdzielczość przeciążenie wybiera konstruktora w dwóch etapach:

  • [..]
  • Jeżeli inicjator nie opłacalne lista-konstruktor stwierdzono, rozdzielczość przeciążenia jest wykonywane ponownie, gdy funkcje kandydujące są konstruktorzy klasy T i liście argumentów składa elementami listy inicjalizatora.

Ponieważ druga linia kompiluje grzywny, występuje niespójność: Powinny być równoważne, jeśli chodzi o przeciążenie rozdzielczość.

+0

Zgadza się, spojrzeć na http://stackoverflow.com/q/32144976/1938163 –

3

Z [class.conv.fct]/2:

Funkcja konwersji może być jawne (7.1.2), w którym to przypadku jest ona uważana tylko konwersji zdefiniowane przez użytkownika w celu bezpośredniego inicjalizacji (8.5).

Pytanie więc, jak zainicjować swoje obiekty. Oczywiście baz jest inicjowany bezpośrednio, więc to działa. W przeciwieństwie do tego, bar jest zainicjowana na liście bezpośredniej, ale nie inicjowana bezpośrednio, dlatego jawna konwersja nie jest dostępna.

+3

Myślę, że nie powiedzie się w Clangu również z nie jawną funkcją konwersji –

+0

@ Piotr. Wow, masz rację, to szalone. To na pewno błąd w Klangie? –

+0

@TavianBarnes Nie wiem, jestem też ciekawy –

2

dzyń nie obchodzi, czy operator konwersji jest explicit czy nie, i wierzę, że jest poprawne ze względu na sformułowania w [over.best.ics].

pierwsze, bezpośrednia inicjalizacja

std::string baz(Foo{}); 

działa zarówno gcc i brzękiem i wyjaśnia [class.conv.fct]/2 jak wspomniano w KerrekSB's answer.

bezpośrednim lista inicjalizacja

std::string bar{Foo{}}; 

z drugiej strony, nie uważa dowolny zdefiniowane przez użytkownika konwersje explicit czy nie.

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

Jednakże rozważając argumentu konstruktora lub funkcji konwersji, zdefiniowane przez użytkownika, który jest kandydat do 13.3.1.3, gdy zostanie wywołany do kopiowania/przenoszenia tymczasowego w drugim kroku inicjowania kopii klasy, 13.3.1.7 podczas przekazywania listy inicjalizatora jako pojedynczego argumentu lub , gdy lista inicjalizatorów ma dokładnie jeden element i konwersja do jakiejś klasy X lub odniesienie do (prawdopodobnie cv-qualif ied) X jest rozpatrywany dla pierwszego parametru konstruktora X lub według 13.3.1.4, 13.3.1.5 lub 13.3.1.6 we wszystkich przypadkach, tylko standardowe sekwencje konwersji i sekwencje konwersji elipsy są uważane za.

+0

Czy to możliwe, że sekcja mówi konkretnie o listach inicjalizujących (np. 'Std :: initializer_list'), a nie o usztywnionych listach startowych? –

+0

I przypuszczam, że jeśli masz rację, to clang jest niewłaściwy dla akceptacji kodu, gdy 'std :: string' jest zamieniane na' int'? –

+0

@Tavian Nie, jestem prawie pewny, że oznacza to listy ze wzmocnionymi początkami, ponieważ 13.3.1.7, o którym tam wspomniałem, obejmuje ogólnie inicjowanie listy. I nie znam odpowiedzi na twoje drugie pytanie. Cytowany akapit wspomniał o "klasie X", więc może to oznacza, że ​​dotyczy tylko typów zdefiniowanych przez użytkownika? Powinieneś dodać obserwację 'int' do raportu o błędzie klang, aby uzyskać odpowiedź na oba. – Praetorian

Powiązane problemy