如何禁用隐式构造函数转换,同时允许复制初始化

jya*_*ard 6 c++ c++11

假设我们有类似的东西:

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回答的错字.谢谢

M.M*_*M.M 3

T blah = U();给出错误,因为正如您正确解释的那样,复制初始化调用隐式转换UT; 但你已经标记了构造函数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)不能使用显式构造函数。