防止构造函数中的意外转换

joh*_*ers 17 c++ explicit-constructor c++11

根据这里,explicit:

指定不允许隐式转换或复制初始化的构造函数和转换运算符(自C++ 11开始).

那么,这两种技术是否相同?

struct Z {
        // ...
        Z(long long);     // can initialize with a long long
        Z(long) = delete; // but not anything smaller
};

struct Z {
        // ...
        explicit Z(long long);     // can initialize ONLY with a long long
};
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 24

不,他们不一样.explicit如果选择了该构造函数,则禁止对该类型的隐式转换 - 参数中的隐式转换无关紧要.delete如果选择了该构造函数,则禁止任何构造,并且可以用于禁止隐式参数转换.

例如:

struct X {
    explicit X(int ) { }
};

void foo(X ) { }

foo(4);      // error, because X's constructor is explicit
foo(X{3});   // ok
foo(X{'3'}); // ok, this conversion is fine
Run Code Online (Sandbox Code Playgroud)

这与delete构造函数是分开的:

struct Y {
    Y(int ) { }
    Y(char ) = delete;
};

void bar(Y ) { }

bar(4);      // ok, implicit conversion to Y since this constructor isn't explicit
bar('4');    // error, this constructor is deleted
bar(Y{'4'}); // error, doesn't matter that we're explicit
Run Code Online (Sandbox Code Playgroud)

这两种技术也是正交的.如果您希望某个类型不可隐式转换,并且只能从一个类型构造int,则可以执行以下两种操作:

struct W {
    explicit W(int ) { }

    template <class T>
    W(T ) = delete;
};

void quux(W );

quux(4);      // error, constructor is explicit
quux('4');    // error, constructor is deleted
quux(4L);     // error, constructor is deleted
quux(W{'4'}); // error, constructor is deleted
quux(W{5});   // ok
Run Code Online (Sandbox Code Playgroud)

  • @Puppy你因为我使用大括号而向我倾倒?真的吗? (2认同)
  • 实际上,Stroustrup也鼓励支撑初始化器(第6.3.5节,"The C++ Programming Language - 4th ed.",BS,2013). (2认同)

eer*_*ika 17

他们不一样.

Z z = 1LL;
Run Code Online (Sandbox Code Playgroud)

以上版本适用于非显式版本,但不适用于显式版本.

声明Zexplicit的构造函数不会阻止构造函数参数从另一个类型转换.它可以防止从参数转换到Z不显式调用构造函数.

下面是显式构造函数调用的示例.

Z z = Z(1LL);
Run Code Online (Sandbox Code Playgroud)

  • 注意,它调用显式构造函数,以及复制/移动构造函数.`Z z(1LL);`只调用显式构造函数. (3认同)

Yak*_*ont 5

explicit阻止隐式转换为您的类型.

您的=delete技术会阻止隐式转换longlong long.

这几乎是无关的.

有4个案例说明了不同之处:

Z z = 1L;
Z z = 1LL;
Run Code Online (Sandbox Code Playgroud)

是从隐式转换longlong longZ.

Z z = Z(1L);
Z z = Z(1LL);
Run Code Online (Sandbox Code Playgroud)

是一个明确的转换longlong longZ.

explicit Z(long long) 块:

Z z = 1L;
Z z = 1LL;
Run Code Online (Sandbox Code Playgroud)

虽然Z(long)=delete块:

Z z = 1L;
Z z = Z(1L);
Run Code Online (Sandbox Code Playgroud)

explicit Z(long long)允许Z z = Z(1L)因为从转换longlong long是隐含的,但无关的显式转换到Z这种情况发生之后.

请注意,在您的4个版本中,混合explicit=delete离开仅Z z=Z(1LL)有效.

(以上假定一个有效的复制或移动构造函数;若否,替换Z z=Z(...)Z z(...)和相同的结论的结果).