标记为“显式”的 C++11 initializer_list 构造函数

Posted

技术标签:

【中文标题】标记为“显式”的 C++11 initializer_list 构造函数【英文标题】:C++11 initializer_list constructor marked "explicit" 【发布时间】:2013-01-26 03:40:32 【问题描述】:

我可以使用显式和初始化列表 ctor 来确保像 a 这样的表达式不会导致意外的隐式转换吗?还有一个想法:应该我担心吗?写a 比简单地写a 不太可能是一个错误,但另一方面,从代码中可能仍不清楚我们正在通过隐式转换构造一个对象。

class Foo

    explicit Foo (std::initializer_list<Bar> ilist)  /*...*/
;

【问题讨论】:

取决于它是什么,我喜欢它。我喜欢能够使用someFunctionWithVectorAsArgument(1, 2, 3); 我同意,但我将 ilist 传递给另一个类的构造函数,这是我不知道的模板参数,我无法判断该类是否具有显式标记的构造函数,或者像您一样使用 1,2,3 是否安全。这就是我问的原因,我想知道它是否像不使用“显式”时所做的常见隐式转换一样危险 恕我直言,将explicit 放在初始化列表构造函数上总是是个坏主意。它没有任何优势,只会在合理尝试构造类型时导致混淆或意外错误。 【参考方案1】:

你当然可以。是否真的应该视情况而定,尽管我认为一般情况下很少见。

【讨论】:

明确表示不允许任何数量的 ilist 项目,还是只允许一个项目?换句话说,它是否使 1,2,3 非法,或者只是 1 是非法的,而 1,2,3 仍然可以? @fr33domlover:这意味着不能隐式使用特定的构造函数。如果有其他构造函数可以让您创建未显式声明的对象,则可能会隐式使用该构造函数。 那我去掉“显式”关键字,我想享受 1,2,3 带来的便利【参考方案2】:

你不能。它确实会导致意外的隐式转换。

但是,意外的隐式转换是不允许的,编译器将拒绝您的程序。然而,这并不能阻止编译器选择或考虑它。示例

 void f(Foo);
 void f(std::vector<Bar>);

 int main() 
   // ambiguous
   f(bar1, bar2, bar3);
 

【讨论】:

那么在这种情况下“显式”有什么作用吗?我不确定我是否理解。我希望 Temple 构造函数采用初始化列表并将其传递给 T 的构造函数,该构造函数采用初始化列表。将 Templ 的构造函数标记为显式是否有用? 为什么这个答案与另一个答案相矛盾......这意味着你们中的一个人在没有意识到的情况下给出了错误的答案...... @fr33domlover 正如我所说,如果选择了“f(Foo)”,则程序格式错误(被编译器拒绝)。构造函数是显式的这一事实不会影响编译器尝试执行哪些函数的选择。如果Foo 有另一个不比Bar 更好的初始化列表构造函数,那么您也会产生歧义。如果Bar 取一个更好,编译器会选择Bar 取一个,并给你一条错误消息,因为它会使用explicit 构造函数。 @fr33domlover 我认为他对参数传递的形式感到困惑。 explicit 的规则对于初始化器列表初始化与它们对于正常初始化的规则是不同的。所以Foo f = a; 不会考虑 explicit 构造函数(即它只会忽略它们),但Foo f = a 不会允许 explicit 构造函数,但它会考虑他们。

以上是关于标记为“显式”的 C++11 initializer_list 构造函数的主要内容,如果未能解决你的问题,请参考以下文章

C++17 中的显式默认构造函数

如何在使用 WCF 的事务性 MSMQ 中将消息显式标记为中毒

本书示例在类声明中使用“显式”关键字。无效吗?

什么特别地将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?

来自 initializer_list 的三元运算符 + C++11 构造函数

C++11之显式转换操作符-explicit