根据经验,C ++总是更喜欢列表初始值设定项而不是值初始值设定项。因此,我的问题是如何强制还支持直接列表初始化的类型的值初始化。这是一个最小的非工作示例:
#include <initializer_list>
using namespace std;
struct foo {
foo(int) {}
foo(initializer_list<char>) {}
};
struct bar {
foo f{256};
};
在此示例中,我希望使用构造函数f
而不是foo(int)
初始化foo(initializer_list<char>)
。但是,GCC和Clang都拒绝代码,因为256对于char来说太大了,这意味着C ++规范需要选择列表初始化器。显然,注释掉foo
的第二个构造函数可以解决问题。定义bar
以便在字段f
上使用值初始化的最简单方法是什么?理想情况下,我可以避免复制初始化f
,因为在我的实例中没有复制构造函数。
更新
澄清一下:当然可以在f
的每个构造函数中显式初始化bar
。但我的问题是关于成员初始化语法的问题,因为在具有大量构造函数的情况下,最好只在一个地方初始化某些字段而不是全部复制代码。
答案 0 :(得分:3)
只要您要求foo
不可复制/可移动,并且您需要foo
拥有可用于代替构造函数的initializer_list
构造函数,这就是行为你得到。因此,如果要解决此问题,则必须更改其中一个事实。
如果你根本无法改变foo
的定义,那么你就搞砸了。抱怨任何拥有该类的人。
第二个事实可能是最容易改变的,但即使这样也不会没有后果:
struct il {};
struct foo {
foo(int) {}
foo(il, initializer_list<char>) {}
};
这完全消除了问题的歧义。 foo{256}
将始终调用单整数构造函数。但是,foo
在技术上没有initializer_list构造函数;相反,您必须使用标记类型il
来使用初始化值列表来调用它:
foo f{il{}, {/*actual list*/}};
这需要更多支撑,但没有真正的替代方案。
请注意,在C ++ 17中,保证省略可以执行此操作:
struct bar {
foo f = foo(256);
};
无论foo
是否可移动。