如何解决C ++ 11统一初始化:初始化列表和多参数构造函数之间的歧义?
当前,我想尽全力围绕C ++ 11的统一初始化。我遇到了这个模棱两可的情况:考虑一个可以从两个参数的构造函数或任何长度的初始化列表构造的类:
class Foo {
public:
Foo(int a,int b) {
std::cout << "constructor 1" << std::endl;
}
Foo(std::initializer_list<int>) {
std::cout << "constructor 2" << std::endl;
}
};
遵循统一的初始化约定,我希望以下方法能起作用:
Foo a (1,2)
打印constructor 1
(duh)
Foo b {1,2}
打印constructor 1
Foo c = {1,2}
打印constructor 2
但是,似乎编译器将Foo b {1,2}
解释为列表初始化,并调用构造函数2。()
语法是在初始化程序时强制编译器考虑其他类型的构造函数的唯一方法-list构造函数存在吗?
解决方法
您可以向构造函数添加一个额外的忽略参数,以在调用站点上指定特定的重载,就像在STL中一样:
#include <iostream>
struct non_init_list_t {};
inline constexpr non_init_list_t non_init_list;
struct Class {
Class(int a,int b,non_init_list_t = non_init_list) { std::clog << "()\n"; }
Class(std::initializer_list<int> list) { std::clog << "{}\n"; }
};
Class a{12,42,non_init_list}; // ()
Class b{12,42}; // {}
Class c(12,42); // ()
,
似乎编译器将Foo b {1,2}解释为列表 初始化,并调用构造函数2。是()语法的唯一方法 强制编译器在其他情况下考虑其他类型的构造函数 初始化列表构造器存在吗?
标准草案的行情很好地解释了这一点:
9.4.5.2 [dcl.init.list](重点是我):
如果构造函数是第一个构造函数,则它是一个初始化列表构造函数 参数类型为std ::: initializer_list或对cv的引用 std :: initializer_list用于某些类型E,或者没有 其他参数,否则所有其他参数都有默认参数 ([dcl.fct.default])。
[注2: Initializer-list构造函数是 在列表初始化中优先于其他构造函数 ([over.match.list])。将初始化程序列表作为参数传递给 C类的构造函数模板C(T)不 创建一个初始化器列表构造函数,因为初始化器列表 参数导致相应的参数为非推导 上下文([temp.deduct.call])。 —尾注]
当非聚合类类型T的对象被列表初始化时,例如 [dcl.init.list]指定执行重载解析 根据本节中的规则或形成 根据[over.ics.list]的列表初始化顺序,重载 分辨率分两个阶段选择构造函数:
-
如果初始化列表不为空或T没有默认构造函数, 首先在候选函数的位置执行 过载解析 是T类的初始化程序列表构造函数 ([dcl.init.list]) 并且参数列表由单个的初始化程序列表组成 论点。
-
否则,或者 如果找不到可行的初始化程序列表构造器 , 重载解析将再次执行,其中 候选函数 是类T 的所有构造函数,参数列表包括 初始化列表的元素。
如果构造函数具有initializer_list
版本,则编译器将首先将其解释为initializer_list
,如果没有initializer_list
版本,则编译器会将其解释为另一个重载版本。
如果编译器将其解释为另一个版本,并且您要调用使用initializer_list
版本的构造函数,则会发生参数的数量和类型与其他ctor相同的情况,这将导致错误。然后,编译器选择initializer_list
版本还是其他版本?因此,使用括号表示法绝对不是initializer_list
版本。如果您的构造函数中没有initializer_list
版本,请不要担心此问题。
顺便说一句,如果您使用auto
自动推断类型,请不要使用统一初始化。它必须将类型解释为initializer_list
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。