C++11 值初始化器与列表初始化器
C++11 value initializer vs list initializer
根据经验,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
,因为在我的真实示例中没有复制构造函数。
更新
澄清一下:当然可以在 bar
的每个构造函数中显式初始化 f
。但我的问题具体是关于成员初始化语法的,因为在有大量构造函数的情况下,最好只在一个地方初始化某些字段,而不是将代码复制到所有地方。
只要你要求 foo
不是 copyable/moveable,并且你要求 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++ 似乎总是更喜欢列表初始化器而不是值初始化器。因此,我的问题是如何强制对也支持直接列表初始化的类型进行值初始化。这是一个最小的非工作示例:
#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
,因为在我的真实示例中没有复制构造函数。
更新
澄清一下:当然可以在 bar
的每个构造函数中显式初始化 f
。但我的问题具体是关于成员初始化语法的,因为在有大量构造函数的情况下,最好只在一个地方初始化某些字段,而不是将代码复制到所有地方。
只要你要求 foo
不是 copyable/moveable,并且你要求 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
是否移动。