假设我们有类似的东西:
class U {
...
}
Run Code Online (Sandbox Code Playgroud)
和:
class T {
T(const U&) { ... }
}
Run Code Online (Sandbox Code Playgroud)
现在我可以像这样声明一个变量:
U foo;
then T blah(foo);
或T blah = foo
我个人更喜欢后者.
现在,我应该将T拷贝构造函数更改为:
class T {
explicit T(const U&) { ... }
}
Run Code Online (Sandbox Code Playgroud)
我只能声明一个变量:
T blah(foo);
T blah = foo;
将给我一个关于将U转换为T的不可能性的编译错误.
http://en.cppreference.com/w/cpp/language/explicit解释了这种行为:"指定构造函数和(自C++ 11以来)不允许隐式转换或复制初始化的转换运算符."
现在,我工作的人要求我们所有的构造函数都是明确的.作为一个老屁,我不喜欢太多改变我的编码风格而忘记T blah = ...风格.
这样的问题是:"有没有办法在允许复制初始化语法的同时使构造函数显式化?"
将构造函数显式化是有充分理由的,而且大多数情况下,您确实希望将其显式化.
在这些情况下,我认为我可以做以下事情:
class T {
template<typename = V>
T(const V&) = delete;
T(const U&) { ... }
}
Run Code Online (Sandbox Code Playgroud)
这将是一个全能的构造函数,禁止所有转换但我真正想要的转换.
想知道是否有一些我可以使用的技巧.
谢谢
编辑:修正了Matt McNabb回答的错字.谢谢
T blah = U();
给出错误,因为正如您正确解释的那样,复制初始化调用隐式转换U
为T
; 但你已经标记了构造函数explicit
。(注意:这不是复制构造函数)
显式转换看起来像这样T blah = T(U());
,并且应该没有错误。
T blah(U());
是一个函数声明(查找最令人烦恼的 parse)。blah
在您的测试用例中,您可能实际上并没有尝试像对象一样使用它,否则您会注意到这个问题。
继续你的问题:
有没有办法在允许复制初始化语法的同时使构造函数显式化?
正如您引用的确切文字所解释的那样,没有explicit
:
指定不允许复制初始化的构造函数。
您必须切换到直接或支撑初始化。恕我直言,无论如何,这是一件好事,复制初始化很麻烦,而且只能避免 MVP;但既然我们可以使用支撑初始化来避免 MVP,那么就不再需要它了。
您可以使用以下任一方法,该方法有效,因为在所有情况下 aT
都是由列表元素直接显式初始化的:
T blah{ U() };
T blah = T{ U() }; // redundant copy/move operation, probably elided
Run Code Online (Sandbox Code Playgroud)
请注意,T blah = { U() };
此处不能使用 ,因为这种形式的初始化(称为copy-list-initialization)不能使用显式构造函数。