C++11 数组初始化不会调用复制构造函数
c++11 array initialization won't call copy constructor
我正在制作一个小类,它使用按大小模板化的数组。这是一些代码。。。
.hpp
template <size_t N>
class KeyCombinationListener
{
public:
KeyCombinationListener(
const std::array<sf::Keyboard::Key, N>& sequence,
std::function<void (void)> fn
);
private:
std::array<sf::Keyboard::Key, N> combo;
std::function<void (void)> callback;
};
.cc
template <size_t N>
KeyCombinationListener<N>::KeyCombinationListener(
const array<sf::Keyboard::Key, N>& sequence, function<void (void)> fn
) : combo(sequence), progress{begin(combo)}, callback{fn}
{
}
在构造函数的成员初始化中,我不能使用combo{sequence}
作为初始值设定项,因为它只接受sf::Keyboard::Key
类型。如果它要求initializer_list
,这是有道理的,但这对我来说似乎很奇怪。对于其他标准容器,我可以使用{}表示法调用复制构造函数。这是std::array
的怪癖吗?或者是我叮当作响的虫子?
为了以防万一,这是我的叮当声版本:
Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9.2
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9
Candidate multilib: .;@m64
Selected multilib: .;@m64
您在C++中遇到了一个缺陷:从单个元素进行列表初始化。C++11和C++14国际标准中规定的行为令人惊讶。我将参考下面的C++14。
std::array
的模板实例化是聚合[array.overview]/2。因此,当从支持的初始化列表初始化std::array
对象时,聚合初始化将不分青红皂白地执行初始化程序的数量[dcl.init.list]/3.1。由于对某些构造的要求(例如,来自一对迭代器),其他容器类无法聚合。
聚合初始化从初始化程序初始化(可能递归地)数据成员。在您的情况下,它将尝试从初始化器sequence
(相同类型)初始化std::array<sf::Keyboard::Key, N>
的第一个数据成员。对于我所知道的std::array
的所有实现,std::array
的第一个数据成员是C样式数组。然后,列表初始化将尝试从原始初始化器sequence
初始化该数组的第一个元素。
示例:
struct aggregate
{
int m[2];
};
aggregate x = {0, 1};
assert(x.m[0] == 0 && x.m[1] == 1);
aggregate y{x}; // error: cannot convert `aggregate` to `int`
最后一行中的初始化将尝试从x
初始化y.m[0]
。
CWG问题1467描述了这一点和一个相关问题,即当没有初始化程序时进行列表初始化。拟议的决议为列表初始化引入了一个(又一个)特例,涵盖了OP中的问题。引用了最近的github草案[dcl.init.list]/3.1
如果
T
是类类型,并且初始值设定项列表具有单个元素类型cvU
,其中U
是T
或从T
派生的类,对象是从该元素初始化(通过复制初始化复制列表初始化,或通过直接初始化直接列表初始化)。
最近草案中的聚合初始化具有较低的"优先级"(3.3),即只有在不满足上述条件的情况下才会执行。
g++(5.0)和clang++(3.7.0)的最新版本甚至在C++11模式下也实现了所提出的解决方案。
- 当从函数参数中的临时值调用复制构造函数时
- 为什么调用复制构造函数而不是移动构造函数?
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 编译器调用复制运算符而不是移动运算符
- push_back std::vector,则重复调用复制构造函数
- 为什么调用复制构造函数来构造空unique_ptr向量?
- 为什么转换运算符调用复制构造函数两次,而等效函数只调用它一次
- 我打算调用initializer_list构造函数,如果存在,则事先调用复制构造函数:为什么?
- C++ - 从移动分配运算符调用复制分配
- 构造函数初始值设定项列表未调用复制构造函数
- 为什么在我的代码中调用复制构造函数而不是移动构造函数?
- std::map 在 [] 上调用默认构造函数,在 insert() 上调用复制构造函数
- 通过引用传递对象时是否调用复制构造函数?
- 如果函数按值传递并按值返回,将调用复制构造函数多少次
- 为什么要抛出引用调用复制构造函数的异常?
- 为什么即使参数标记为"const",也会调用复制构造函数?
- Clang-Tidy:移动构造函数通过调用复制构造函数来初始化类成员
- 为什么当我添加一个不同的对象(复制构造函数中的参数)时调用复制构造函数?
- 为什么调用复制构造函数,当我只返回对象 c++ 的引用时
- 为什么在下面的代码中调用复制构造函数两次