如果将不正确的参数类型传递给struct initialiser列表,为什么编译器不会生成编译错误?

T M*_*T M 39 c++ struct c++11

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

struct MyStruct
{
    MyStruct(const int value)
        : value(value)
    {
    }
    int value;
};
Run Code Online (Sandbox Code Playgroud)

和以下对象:

int main()
{
    MyStruct a (true);
    MyStruct b {true};
}
Run Code Online (Sandbox Code Playgroud)

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

  1. 为什么我没有收到任何编译错误?
  2. 如何使编译器帮助我检测到这一点?(最初,该结构被写入有bool数据,但一段时间后,代码改变,bool变得int和介绍了几个错误.)

Bar*_*rry 72

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

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

struct MyStruct
{
    explicit MyStruct(int i) : value(i) { }

    template <typename T>
    MyStruct(T t) = delete;

    int value;
};
Run Code Online (Sandbox Code Playgroud)

在这里,MyStruct{true}并且MyStruct(false)将产生调用MyStruct::MyStruct<bool>,其被定义为已删除,因此是不正确的.

这种优势的好处static_assert是所有类型特征实际上都会产生正确的值.例如,std::is_constructible<MyStruct, bool>std::false_type.

  • @MM这是标准[称之为](http://eel.is/c++draft/dcl.init.list#7)的好坏,所以我会用它来保持一致性. (5认同)
  • 是的,那更好. (4认同)
  • "缩小"是一个误称......它暗示一个比另一个更窄,但是`int-> double`和`double-> int`都被认为是"缩小".也许"有损"会是一个更好的描述 (2认同)

Ker*_* SB 15

这是一种结构,允许您只从一个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;
};
Run Code Online (Sandbox Code Playgroud)

这是因为此构造函数模板所需的模板参数推导将生成参数的确切类型而不执行转换,因此您可以对该类型执行测试.

您或许也应该使用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) {}

    // ...
Run Code Online (Sandbox Code Playgroud)

  • 我知道这个问题被标记为C++ 11,但我认为值得注意的是`static_assert`在以前的版本中不存在. (3认同)

Ric*_*ges 8

最简单的解决方案是声明一个bool构造函数,因为删除不是吗?

struct MyStruct
{
    MyStruct(bool) = delete;

    MyStruct(const int value)
    : value(value)
    {
    }
    int value;
};
Run Code Online (Sandbox Code Playgroud)

示例错误输出:

...
/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.
Run Code Online (Sandbox Code Playgroud)

  • @LightnessRacesinOrbit没有,short-> int没有缩小,但我也不能看到(语义上)允许转换的问题.它是一种自然转换,与短整数的所有其他用途兼容.防止bool实例化(有点)是有道理的,因为bool在人类推理方面与int的含义略有不同. (4认同)

Lig*_*ica 7

因为a bool可以隐式转换int.

这是一个你无法关闭的语言功能,抱歉.