Considerate questo pezzo di codice C++ 11:Restringendo conversione a bool nella lista-inizializzazione - strano comportamento
#include <iostream>
struct X
{
X(bool arg) { std::cout << arg << '\n'; }
};
int main()
{
double d = 7.0;
X x{d};
}
C'è una conversione restringimento da un doppio a un bool nella inizializzazione del x
. Secondo la mia comprensione dello standard, questo è un codice mal formato e dovremmo vedere qualche diagnostica.
Visual C++ 2013 genera un errore:
error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion
Tuttavia, entrambi i Clang 3.5.0 e GCC 4.9.1, utilizzando le seguenti opzioni
-Wall -Wextra -std=c++11 -pedantic
compilare questo codice con senza errori e nessun avviso. L'esecuzione del programma produce uno 1
(nessuna sorpresa).
Ora, andiamo più in profondità in un territorio strano.
Change X(bool arg)
-X(int arg)
e, improvvisamente, abbiamo un errore dal Clang
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
e un avvertimento da GCC
warning: narrowing conversion of 'd' from 'double' to 'int' inside { } [-Wnarrowing]
Questo sembra più simile a quello che mi aspettavo.
Ora, tenere l'argomento bool
costruttore (cioè, ripristinare X(bool arg)
), e cambiare double d = 7.0;
a int d = 7;
. Di nuovo, un errore di restringimento da Clang, ma GCC non rilascia alcuna diagnostica e compila il codice.
Ci sono alcune varianti di comportamento che possiamo ottenere se passiamo la costante direttamente al costruttore, alcune strane, alcune previste, ma non le elencherò qui - questa domanda sta diventando troppo lunga.
Direi che questo è uno dei rari casi in cui VC++ è giusto e Clang e GCC sono sbagliate quando si tratta di standard di conformità, ma, date le rispettive track record di questi compilatori, sono ancora molto titubante su questo.
Cosa pensano gli esperti?
riferimenti standard (citazioni dal documento standard finale per C++ 11, ISO/IEC 14.882-2011):
In 8.5.4 [dcl.init.list] paragrafo 3, abbiamo avere:
— 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.
nella stessa sezione, al paragrafo 7, abbiamo:
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 ]
in 3.9.1 [di base.fondamentale] comma 7, abbiamo:
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.
(stavo iniziando a mettere in discussione tutto ciò che in questa fase ...)
Ehi, da dove tutti i commenti vanno? Alcuni di essi contenevano informazioni utili per diagnosticare il problema, in particolare per Clang. – bogdan
Alcuni di questi commenti sarebbero stati molto utili per archiviare i bug report, non capisco perché sono stati tutti cancellati, forse chiedendo su [meta] (http://meta.stackoverflow.com/) può aiutare, io Adesso hai il tempo. Puoi anche provare una bandiera personalizzata, ma non sai per quanto tempo prima verrà applicata. –
@dyp non è sicuro che lo vedrete dato che il vostro commento è stato cancellato ma i vostri utili collegamenti al codice sorgente clang sono stati rimossi e sarebbe utile riaverli. –