#include <initializer_list>
#include <vector>
struct test
{
using t = std::vector<test>;
test(t const &v)
{
}
test(t &&v)
{
}
test(std::initializer_list<test> v)
: test{t{v}} //error
{
}
};
Run Code Online (Sandbox Code Playgroud)
无论锵和GCC抱怨说,第三个构造函数,一个以初始化列表中,代表们本身.我不明白这是怎么可能的,因为你无法从向量构造初始化列表.
通过用圆括号替换外部花括号来修复错误是微不足道的,但为什么这首先是一个问题呢?这几乎相同的程序编译得很好:
#include <initializer_list>
struct a {};
struct b {};
struct test
{
test(a const &)
{
}
test(a &&)
{
}
test(std::initializer_list<b> v)
: test{a{}} //no error, still using curly braces
{
}
};
Run Code Online (Sandbox Code Playgroud)
有趣的是,使用上面的第二个例子,如果你用替换b,错误会重新出现test.有人能解释一下这里发生了什么吗?
类型t{v}是std::vector<test>.我们的想法是init-list构造函数总是优先于任何其他构造函数,因此test{t{v}}首先尝试调用init-list构造函数(如果存在),以及类型是否兼容.在你的情况下,这是可能的,因为test它本身可以从std::vector<test>(通过你的前2个构造函数)隐式构造,因此编译器最终委托给init-list构造函数,因此错误.
在第二种情况下,没有歧义,因为类型a{}不再可以隐式转换std::initializer_list<b>.
explicit在第一个示例中创建构造函数,或者调用基础构造函数test(t{v}),并且您的歧义将消失(编译器将不再执行隐式转换).
一个更简单的例子(在这里生活)表现出与第一个例子基本相同的行为:
#include <initializer_list>
struct test
{
/*explicit*/ test(int){} // uncomment explicit and no more errors
test( std::initializer_list<test> v)
: test{42} {} // error, implicitly converts 42 to test(42) via the test(int)
};
int main(){}
Run Code Online (Sandbox Code Playgroud)
处理init-list构造函数的标准的相关部分是§13.3.1.7/ 1 [over.match.list] - 下面的引文摘自@Praetorian现在删除的答案 -
当非聚合类类型T的对象被列表初始化,使得8.5.4指定根据本节中的规则执行重载解析时,重载决策分两个阶段选择构造函数:
- 最初,候选函数是初始化器类的-list构造函数(8.5.4)T和参数列表由初始化列表作为单个参数组成.
- 如果找不到可行的初始化列表构造函数,则再次执行重载解析,其中候选函数是类的所有构造函数,T参数列表由初始化列表的元素组成.
| 归档时间: |
|
| 查看次数: |
1411 次 |
| 最近记录: |