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

时间:2015-05-04 05:02:15

标签: c++ c++11

假设我们有类似的东西:

class U {
  ...
}

class T {
  T(const U&) { ... }
}

现在我可以像这样声明一个变量: U foo;然后T blah(foo);T blah = foo

我个人更喜欢后者。

现在,我应该将T拷贝构造函数更改为:

class T {
  explicit T(const U&) { ... }
}

我只能声明一个变量: 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&) { ... }
}

这将是一个全能的构造函数,禁止所有转换,但我真正想要的转换。

想知道是否有一些我可以使用的技巧。

由于

编辑:修正了Matt McNabb回答中指出的拼写错误。感谢

1 个答案:

答案 0 :(得分:3)

T blah = U();给出错误,因为正如您正确解释的那样,复制初始化调用将U隐式转换为T;但是你已经标记了构造函数explicit。 (注意:这不是复制构造函数)

显式转换看起来像T blah = T(U());,这应该没有错误。

T blah(U());是一个函数声明(查找most vexing parse)。在你的测试用例中,你可能并没有真正尝试使用blah,就好像它是一个对象一样,否则你会注意到这个问题。

转到你的问题:

  

有没有办法在允许复制初始化语法的同时使构造函数显式化?

正如您引用的关于explicit的确切文字所解释的那样:

  

指定不允许复制初始化的构造函数。

您必须切换到直接或支持初始化。恕我直言,无论如何,复制初始化很麻烦,只对躲避MVP有好处;但现在我们可以避免使用支持初始化的MVP,它根本不再需要。

您可以使用以下任何一种方法,因为在所有情况下,T都由list元素直接显式初始化:

T blah{ U() };
T blah = T{ U() };  // redundant copy/move operation, probably elided

请注意,此处不能使用T blah = { U() };,因为这种初始化形式(称为 copy-list-initialization )不能使用显式构造函数。