为什么编译器会在编译错误时将不正确的参数types传递给struct initialiser list?

我定义了一个结构体,它有一个构造函数:

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

和以下对象:

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

但是我没有收到任何编译错误,无论是MVS2015或Xcode 7.3.1。

  1. 为什么我没有收到任何编译错误?
  2. 我如何让编译器帮我检测到这个? (最初,结构被写成具有bool数据,但一段时间后,代码改变了, bool变成了int ,引入了一些错误。)

一个bool可以隐式转换为一个int值的方式保存。 使用大括号初始化的唯一不允许的转换是缩小转换 (例如反转bool{42} )。

如果你想确保你的类只能int来构造,那么直接的方法就是delete所有其他的构造函数:

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

在这里, MyStruct{true}MyStruct(false)将调用MyStruct::MyStruct<bool> ,它被定义为删除,因此是不合格的。

这个优于static_assert是,所有的types特征实际上会产生正确的值。 例如, std::is_constructible<MyStruct, bool>std::false_type

这是一个允许你只从int值初始化你的类的构造:

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

这是因为此构造函数模板所需的模板参数推导将产生参数的确切types而不执行转换,因此您可以对该types执行testing。

你也许应该也可以使用SFINAE来约束构造函数,这样MyStruct就不会出现任何构造。

此外,你应该也可以使构造函数模板explicit使随机整数不成为MyStruct实例。

换句话说,我会这样写:

 struct MyStruct { template <typename T, typename = std::enable_if_t<std::is_same<T, int>::value>> MyStruct(T t) : value(t) {} // ... 

最简单的解决scheme是声明一个布尔构造函数为删除不是吗?

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

示例错误输出:

 ... /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. 

因为一个bool可以隐式转换为一个int

这是一个语言function,你不能closures,对不起。

值true被转换为值1(int)。