Pourquoi le compilateur ne génère-t-il pas d’erreurs de compilation si un type d’argument incorrect est transmis à une liste d’initialisation de struct?

J’ai défini une structure, qui a un constructeur:

struct MyStruct { MyStruct(const int value) : value(value) { } int value; }; 

et les objects suivants:

 int main() { MyStruct a (true); MyStruct b {true}; } 

Mais je n’ai reçu aucune erreur de compilation, que ce soit avec MVS2015 ou Xcode 7.3.1.

  1. Pourquoi je ne reçois aucune erreur de compilation?
  2. Comment puis-je faire en sorte que le compilateur m’aide à détecter cela? (Initialement, la structure a été écrite pour avoir des données bool , mais après un certain temps, le code a changé et bool est devenu int et plusieurs bogues ont été introduits.)

Un bool peut être implicitement converti en int de manière à préserver les valeurs. Les seules conversions non autorisées avec l’initialisation des accolades sont des conversions restreintes (par exemple, l’inverse bool{42} ).

Si vous voulez vous assurer que votre classe est constructible uniquement avec int , la méthode directe consiste simplement à delete tous les autres constructeurs:

 struct MyStruct { explicit MyStruct(int i) : value(i) { } template  MyStruct(T t) = delete; int value; }; 

Ici, MyStruct{true} et MyStruct(false) des appels à MyStruct::MyStruct , qui est défini comme supprimé et donc mal formé.

L’avantage de ceci sur static_assert est que tous les traits de type donneront effectivement les valeurs correctes. Par exemple, std::is_constructible est std::false_type .

Voici une construction qui vous permet d’initialiser uniquement votre classe à partir d’une valeur int :

 #include  struct MyStruct { template  MyStruct(T t) : value(t) { static_assert(std::is_same::value, "Bad!"); } int value; }; 

En effet, la déduction des arguments de modèle requirejse par ce modèle de constructeur génère le type exact de l’argument et n’effectue pas de conversions. Vous pouvez donc effectuer des tests sur ce type.

Vous devriez peut-être aussi ou plutôt utiliser SFINAE pour contraindre le constructeur, de sorte que MyStruct ne se présente pas comme étant constructible.

De plus, vous devriez probablement rendre le modèle de constructeur explicit pour que les entiers aléatoires ne deviennent pas des instances de MyStruct .

En d’autres termes, je l’écrirais comme ça:

 struct MyStruct { template ::value>> MyStruct(T t) : value(t) {} // ... 

La solution la plus simple consiste à déclarer un constructeur bool comme supprimé, non?

 struct MyStruct { MyStruct(bool) = delete; MyStruct(const int value) : value(value) { } int value; }; 

exemple de sortie d’erreur:

 ... /Users/xxxxxxx/play/fast_return/skeleton/main.cpp:68:14: error: call to deleted constructor of 'MyStruct' MyStruct b {true}; ^ ~~~~~~ /Users/xxxxxxx/play/fast_return/skeleton/main.cpp:57:9: note: 'MyStruct' has been explicitly marked deleted here MyStruct(bool) = delete; ^ 2 errors generated. 

Parce qu’un bool peut être implicitement converti en un int .

Ceci est une fonctionnalité de langue que vous ne pouvez pas désactiver, désolé.

la valeur true est convertie en valeur 1 (int).