C++17如何调用空initializer_list构造函数及与C++14的差异
C14与C17下
Foo({})行为差异解答 1. 行为不同的核心原因
这个差异来源于C++17引入的**强制拷贝消除(mandatory copy elision)**配套的初始化语义规则变更:
- C++14的规则下,
Foo({})只能被解释为「调用Foo的构造函数,传入一个由{}初始化的实参」。此时重载决议会匹配到形参为initializer_list<int>的构造函数:空花括号{}可以直接初始化出一个空的initializer_list<int>实例,符合构造函数的参数要求,因此输出init_list。 - C17的规则新增了对
T({args})形式的语义解释路径:如果T{args}是合法表达式,那么T({args})可以匹配到编译器自动生成的隐式拷贝/移动构造函数,相当于T(T{args})。由于C17强制要求拷贝消除,不需要实际调用拷贝/移动构造函数,整个表达式会直接优化为调用T{args}对应的构造函数。放到这个例子里,Foo{}是合法的默认构造调用,因此Foo({})被直接优化为默认构造调用,输出empty,这个路径的重载优先级高于匹配initializer_list构造函数的路径。
2. C++17下构造传入空initializer_list的Foo实例的方法
有三种常用的写法可以绕过默认构造的匹配优先级,强制调用initializer_list版本的构造函数:
- 显式构造空的
initializer_list<int>实例传入:Foo(std::initializer_list<int>{}); - 传入双层空花括号,让编译器无法将其解释为构造Foo临时对象的初始化器:
Foo({{}}); - 使用列表初始化语法,列表初始化会优先匹配
initializer_list构造函数:Foo{{}};
内容的提问来源于stack exchange,提问作者hczstev
相关产品推荐
相关产品推荐

