C++11 值初始化器与列表初始化器

标签 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 ,因为在我的真实示例中没有复制构造函数。

更新

澄清一下:当然可以初始化 fbar 的每个构造函数中显式显示.但我的问题具体是关于成员初始化语法的,因为在有大量构造函数的情况下,最好只在一个地方初始化某些字段,而不是将代码复制到所有地方。

最佳答案

只要您要求 foo 不可复制/移动,并且您要求 foo 有一个可以使用的 initializer_list 构造函数这不是构造函数,而是您获得的行为。因此,如果你想解决这个问题,你必须改变这些事实之一。

如果您根本无法更改 foo 的定义,那您就完蛋了。向类(class)的拥有者投诉。

第二个事实可能是最容易改变的,但即便如此也并非没有后果:

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

关于C++11 值初始化器与列表初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44792380/

相关文章:

c++ - 前向声明类模板的成员枚举

c++ - 使用 std::initialiser_list 显式初始化一个变量

c++ - 初始化指向常量数组的指针

c++ - 在运行时检查操作系统正在运行哪种语言

c++ - 具有相同签名的模板不会导致编译器错误

C++:在初始化列表中初始化对 ofstream 的引用

c++ - 变长初始化器列表

c++ - 重用字符串流而不需要重新分配

c++ - 使用 while 进行条件赋值

C++ vector 变化类型