C ++ 11值初始化程序与列表初始化程序

时间:2017-06-28 01:42:27

标签: c++ c++11 initializer-list

根据经验,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。但我的问题是关于成员初始化语法的问题,因为在具有大量构造函数的情况下,最好只在一个地方初始化某些字段而不是全部复制代码。

1 个答案:

答案 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是否可移动。