19

根据这里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
};
4

5 回答 5

27

不,它们不一样。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

这与构造函数是分开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

这两种技术也是正交的。如果您希望一个类型不能被隐式转换并且只能从一个 精确构造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
于 2016-04-19T15:00:05.707 回答
19

它们并不相同。

Z z = 1LL;

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

将构造函数声明为Z显式不会阻止构造函数参数从另一种类型的转换。Z它可以防止在不显式调用构造函数的情况下从参数转换为。

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

Z z = Z(1LL);
于 2016-04-19T14:59:47.113 回答
6

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

您的=delete技术阻止了从longto 的隐式转换long long

这些几乎是无关的。

有4个案例可以说明差异:

Z z = 1L;
Z z = 1LL;

是从longlong long到的隐式转换Z

Z z = Z(1L);
Z z = Z(1LL);

是从longlong long到的显式转换Z

explicit Z(long long)块:

Z z = 1L;
Z z = 1LL;

Z(long)=delete块:

Z z = 1L;
Z z = Z(1L);

explicit Z(long long)允许,Z z = Z(1L)因为从longto的转换是隐式的,但与之后发生long long的显式转换无关。Z

请注意,explicit和的混合=deleteZ z=Z(1LL)在您的 4 个版本中有效。

(以上假定有效的复制或移动ctor;如果不是,则替换Z z=Z(...)Z z(...)并得出相同的结论)。

于 2016-04-19T15:19:15.723 回答
2
struct Zb {
        Zb(long long)
        {};     // can initialize with a long long
        Zb(long) = delete; // but not anything smaller
    };

struct Za {
        // ...
        explicit Za(long long)
        {};     // can initialize ONLY with a long long
    };

int main()
{
    Za((long long)10);  // works
    Za((long)10);       // works    

    Zb((long long)10);  // works
    Zb((long)10);       // does not work

    return 0;
}

您的示例需要显式删除。

直播:http ://cpp.sh/4sqb

于 2016-04-19T15:05:18.567 回答
1

他们不一样。

来自标准工作草案n4296

12.3.1 - [class.conv.ctor]:
1没有函数说明符显式声明的构造函数指定从其参数的类型到其类的类型的转换。这样的构造函数称为转换构造函数

2显式构造函数像非显式构造函数一样构造对象,但仅在显式使用直接初始化语法 (8.5) 或强制类型转换 (5.2.9, 5.4) 的情况下这样做。默认构造函数可以是显式构造函数;这样的构造函数将用于执行默认初始化或值初始化(8.5)。

后面分别分别举例:

struct X {
    X(int);
    X(const char*, int =0);
    X(int, int);
};

void f(X arg) {
    X a = 1;        // a = X(1)
    X b = "Jessie"; // b = X("Jessie",0)
    a = 2;          // a = X(2)
    f(3);           // f(X(3))
    f({1, 2});      // f(X(1,2))
}

使用显式构造函数:

struct Z {
    explicit Z();
    explicit Z(int);
    explicit Z(int, int);
};

Z a;                      // OK: default-initialization performed
Z a1 = 1;                 // error: no implicit conversion
Z a3 = Z(1);              // OK: direct initialization syntax used
Z a2(1);                  // OK: direct initialization syntax used
Z* p = new Z(1);          // OK: direct initialization syntax used
Z a4 = (Z)1;              // OK: explicit cast used
Z a5 = static_cast<Z>(1); // OK: explicit cast used
Z a6 = { 3, 4 };          // error: no implicit conversion
于 2016-04-19T15:13:33.723 回答