2017-05-05 93 views
8

Przetestowałem poniższy kod z 3 kompilatorami i otrzymałem 3 różne wyniki: błąd, ostrzeżenie i ok.konwersja z nullptr_t na bool: poprawny czy nie?

  • GCC (5,3): Błąd: nieprawidłowy zdefiniowana przez użytkownika konwersja z 'std :: nullptr_t' do 'const Thing &'
  • dzyń (3.8): ostrzeżenie: niejawna konwersja nullptr stałą do 'bool'
  • MSVC (14,1): nie ma błędu, bez ostrzeżenia

Który kompilator jest poprawna? Wiem, że jest to trywialna konwersja między typem wskaźnika a bool. Ale co z tymi std::nullptr_t i bool?

(w celu Szczęk i MSVC oba dobrze z kodu. Clang jest trochę więcej komunikatów w pozytywny sposób.)

struct Thing 
{ 
    Thing(bool) {} 
}; 

void addThing(const Thing&){} 

int main() 
{ 
    addThing(nullptr); // warning or error on this line 
} 

Odpowiedz

8

Jest nieważne. Zgodnie z zasadą boolean conversions:

A prvalue of type std::nullptr_t , including nullptr , can be converted to a prvalue of type bool in context of direct-initialization. The resulting value is false .

cytaty z normą, §7.14/1 Boolean conversions [conv.bool]

For direct-initialization, a prvalue of type std​::​nullptr_­t can be converted to a prvalue of type bool ; the resulting value is false .

Konwersja jest dozwolony tylko dla direct-initialization, ale nie copy-intialization, który w tym obudowę do przenoszenia argument funkcji przez wartość. na przykład

bool b1 = nullptr; // invalid 
bool b2 {nullptr}; // valid 

Tak więc GCC jest poprawne. Ale Clang też się nie myli; standard wymaga jedynie, aby kompilator "wystawiał diagnozę", gdy program jest źle sformułowany, więc musi ci powiedzieć, że coś się dzieje, po czym może zrobić cokolwiek.

Zobacz Does the C++ standard specify that for some cases the compiling should fail with an error?

+0

Czy jestem jedyną osobą, której niepokoi logiczna niekonsekwencja? (nie sama odpowiedź). Jestem pewien, że zostało to wykonane z innych powodów, ale to * naprawdę * uderza mnie jako przypadek, w którym żaden nie powinien działać pod nieobecność operatora '_cast'. –

+1

@BrettHale Moją interpretacją jest to, że 'nullptr' może być niejawnie konwertowane tylko na wskaźnik zerowy (dowolnego typu wskaźnika i dowolnego wskaźnika na typ pręta). Konwersja na 'bool' musi być wyraźna, ale nadal dozwolona (dla spójności innych wskaźników?). – songyuanyao

+1

@ Brett Hale Nie uważam tego za niekonsekwentny. Wywołanie konstruktora jawnie niespodzianki, wywołuje konstruktory, które zostały oznaczone jako wyraźne, co jest dokładnie jedną z rzeczy, które zrobi rzut statyczny! Są to typy pierwotne, więc nie mają dosłownie konstruktorów, ale idea jest taka sama. –