[英]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
技術會阻止從long
到long long
隱式轉換。
這幾乎是無關的。
有4個案例說明了不同之處:
Z z = 1L;
Z z = 1LL;
是從long
和long long
到Z
的隱式轉換。
Z z = Z(1L);
Z z = Z(1LL);
是從long
和long 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)
因為從long
到long 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.