簡體   English   中英

防止構造函數中的意外轉換

[英]Prevent undesired conversion in constructor

根據這里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
};

不,他們不一樣。 如果選擇了該構造函數,則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

他們不一樣。

Z z = 1LL;

以上版本適用於非顯式版本,但不適用於顯式版本。

聲明Z explicit的構造函數不會阻止構造函數參數從另一個類型轉換。 它可以防止從參數到Z的轉換,而無需顯式調用構造函數。

下面是顯式構造函數調用的示例。

Z z = Z(1LL);

explicit塊隱式轉換為您的類型

您的=delete技術會阻止從longlong long隱式轉換。

這幾乎是無關的。

有4個案例說明了不同之處:

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

是從longlong longZ的隱式轉換。

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

是從longlong longZ的顯式轉換。

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)因為從longlong long的轉換是隱式的,但與之后發生的顯式轉換為Z無關。

請注意, explicit=delete的混合僅在您的4個版本中留下Z z=Z(1LL)有效。

(以上假設有效副本或移動ctor;如果不是,則用Z z=Z(...)替換Z z=Z(...) Z z(...)並得出相同的結論)。

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

他們不一樣。

從標准工作草案n4296

12.3.1 - [class.conv.ctor]:
1 使用function-specifier explicit聲明的構造函數指定從其參數類型到其類類型的轉換。 這樣的構造函數稱為轉換構造函數

2顯式構造函數與非顯式構造函數一樣構造對象,但僅在顯式使用直接初始化語法(8.5)或強制轉換(5.2.9,5.4)的情況下才這樣做。 默認構造函數可以是顯式構造函數; 這樣的構造函數將用於執行默認初始化或valueinitialization(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM