In primo luogo, perché restringere? Che viene dal §5/10:
Molti operatori binari che si aspettano operandi di tipo aritmetico o di enumerazione causano conversioni e producono tipi di risultato in modo simile. Lo scopo è quello di produrre un tipo comune, che è anche il tipo del risultato. Questo modello è chiamato conversioni aritmetiche abituali, che sono definite come segue:
- [..]
- Altrimenti, le promozioni integrali (4.5) sono eseguite su entrambi gli operandi.
dove la promozione integrale è definito in 4.5/1:
Una prvalue di tipo intero diverso da bool
, char16_t
, char32_t
o wchar_t
cui rango conversione intero (4.13) è inferiore alla il grado int
può essere convertito in un valore di tipo int
se int
può rappresentare tutti i valori del tipo di origine; in caso contrario, il valore di origine può essere convertito in un valore di tipo unsigned int
.
Nel nostro caso, allora, abbiamo decltype(char + char)
è int
perché la conversione rango char
s' meno di int
in modo che entrambi sono promossi al int
prima della chiamata a operator+
.Ora, abbiamo int
s che stiamo passando ad un costruttore che prende char
s. Per definizione (§8.5.4/7, specificamente 7,4):
Un restringendo conversione è una conversione implicita
(7,4) - da un tipo intero o tipo di enumerazione senza ambito di un tipo intero che non può rappresentare tutti i valori del tipo originale, tranne quando la fonte è un'espressione costante il cui valore dopo le promozioni integrali si adatta al tipo di destinazione.
che è esplicitamente vietato in lista-inizializzazione specificamente come da §8.5.4/3 (sottolineatura mia, il "vedi sotto" in realtà si riferisce a quello che ho appena copiato in precedenza):
Lista- inizializzazione di un oggetto o di riferimento di tipo T
è definito come segue
- [..]
- Altrimenti, se T
è un tipo di classe, i costruttori sono considerati. I costruttori applicabili sono enumerati e il migliore viene scelto tramite la risoluzione di sovraccarico (13.3, 13.3.1.7). Se per convertire uno qualsiasi degli argomenti è necessaria una conversione di restringimento (vedere di seguito), il programma è malformato. [...]
Questo è il motivo per cui il vostro vec3<T>{int, int, int}
ti dà un avvertimento: il programma è mal formata a causa di promozione intero che richiede una conversione restringimento su tutte le espressioni. Ora, l'affermazione sul "mal formato" si pone specificamente solo nel contesto dell'inizializzazione delle liste. Questo è il motivo per cui se si inizializza il vostro vettore, senza {}s
, non si vede che l'avvertimento:
vec3<T> operator-(const vec3<T> &other) {
// totally OK: implicit conversion from int --> char is allowed here
return vec3<T>(x - other.x, y - other.y, z - other.z);
}
Come per risolvere questo problema - basta chiamare il costruttore senza lista-inizializzazione è probabilmente la soluzione più semplice. In alternativa, è possibile continuare a utilizzare list-inizializzazione e proprio template vostro costruttore:
template <typename A, typename B, typename C>
vec3(A xx, B yy, C zz)
: x(xx) // note these all have to be()s and not {}s for the same reason
, y(yy)
, z(yy)
{ }
Date un'occhiata alla discussione in questo [bug report GCC] (https://gcc.gnu.org/bugzilla/show_bug. cgi? id = 44500), in particolare [risposta di Jonathan Wakely] (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44500#c3) –
'{}' cattura le conversioni restrittive (rendendo il codice illecito formata). '()' non lo fa. O stai chiedendo perché si sta restringendo? –
Sì, perché si restringe? – hidayat