Rozważmy następujący fragment kodu C++ 11:Zawężenie konwersja do bool w liście inicjalizacji - dziwne zachowanie
#include <iostream>
struct X
{
X(bool arg) { std::cout << arg << '\n'; }
};
int main()
{
double d = 7.0;
X x{d};
}
istnieje konwersja zwężenie z podwójnym do bool w inicjalizacji x
. Zgodnie z moim rozumieniem normy, jest to źle sformułowany kod i powinniśmy zobaczyć jakąś diagnostykę.
Visual C++ 2013 wystawia błąd:
error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion
Jednak oba Clang 3.5.0 i GCC 4.9.1, wykorzystując następujące opcje
-Wall -Wextra -std=c++11 -pedantic
skompilować ten kod z bez błędów i brak ostrzeżeń. Uruchomienie programu wyprowadza 1
(nic dziwnego).
Teraz przejdźmy głębiej w dziwne terytorium.
Zmień X(bool arg)
do X(int arg)
i nagle mamy błąd z Clang
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
i ostrzeżenia z GCC
warning: narrowing conversion of 'd' from 'double' to 'int' inside { } [-Wnarrowing]
wygląda to bardziej jak czego się spodziewałem.
Teraz utrzymać bool
konstruktora argumentu (czyli przywrócić X(bool arg)
) i zmień double d = 7.0;
do int d = 7;
. Ponownie, zwężający się błąd z Clang, ale GCC nie wydaje żadnej diagnostyki i kompiluje kod.
Istnieje kilka innych wariantów zachowania, które możemy uzyskać, jeśli przekazujemy stałą bezpośrednio konstruktorowi, niektóre dziwne, inne się tego spodziewają, ale nie będę ich tutaj wymieniać - to pytanie jest zbyt długie, jak jest.
powiedziałbym, jest to jeden z nielicznych przypadków, kiedy VC++ jest słuszne i Clang i GCC są złe, jeśli chodzi o standardowej zgodności, ale, biorąc pod uwagę odpowiednie udokumentowane tych kompilatorów, jestem wciąż bardzo się wahają.
Co sądzą eksperci?
referencje standardowe (cytaty z końcowego dokumentu standardowego dla C++ 11, ISO/IEC 14882-2011):
W 8.5.4 [dcl.init.list] ustęp 3, my posiadają:
— Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed.
w tym samym rozdziale, w paragrafie 7, mamy:
A narrowing conversion is an implicit conversion
— from a floating-point type to an integer type, or
— from long double to double or float, or from double to float, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented (even if it cannot be represented exactly), or
— from an integer type or unscoped enumeration type to a floating-point type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type, or
— from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression and the actual value after conversion will fit into the target type and will produce the original value when converted back to the original type.
[ Note: As indicated above, such conversions are not allowed at the top level in list-initializations.—end note ]
w 3.9.1 [podstawowy.fundamentalne] pkt 7, mamy:
Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively called integral types.48 A synonym for integral type is integer type.
(zacząłem kwestionować wszystko, co na tym etapie ...)
Hej, gdzie się wszyscy komentarze iść? Niektóre z nich zawierały przydatne informacje do diagnozowania problemu, w szczególności dla Clanga. – bogdan
Niektóre z tych komentarzy byłyby bardzo przydatne przy wypełnianiu zgłoszeń błędów, nie rozumiem, dlaczego zostały one usunięte, być może zapytanie [meta] (http://meta.stackoverflow.com/) może pomóc, teraz nie ma czasu. Możesz również wypróbować niestandardową flagę, ale nie wiesz, jak długo będzie ona działała. –
@dyp nie jestem pewien, że to zobaczysz, ponieważ twój komentarz został usunięty, ale użyteczne linki do kodu źródłowego klang zostały usunięte i byłoby pomocne, aby je odzyskać. –