[英]c++11 array initialization won't call copy constructor
I'm making a little class that uses an array templated on its size.我正在创建一个小类,它使用一个以它的大小为模板的数组。 Here's some code...
这是一些代码...
.hpp .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 .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}
{
}
In the member initialization of the constructor, I can't use combo{sequence}
as the initializer because it only accepts sf::Keyboard::Key
types.在构造函数的成员初始化中,我不能使用
combo{sequence}
作为初始化器,因为它只接受sf::Keyboard::Key
类型。 This makes sense if it's asking for an initializer_list
, but this seems strange to me.如果它要求一个
initializer_list
,这是有道理的,但这对我来说似乎很奇怪。 With other standard containers I can call a copy constructor using {} notation just fine.对于其他标准容器,我可以使用 {} 表示法调用复制构造函数就好了。 Is this a quirk with
std::array
?这是
std::array
的怪癖吗? Or maybe a bug in my clang?或者也许是我的叮当声中的一个错误?
Just in case it helps, here's my clang version:以防万一它有帮助,这是我的叮当版本:
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
You've encountered a defect in C++: list-initialization from a single element.您在 C++ 中遇到了一个缺陷:从单个元素进行列表初始化。 The behaviour specified in the C++11 and C++14 International Standard is surprising.
C++11 和 C++14 国际标准中指定的行为令人惊讶。 I'll refer to C++14 below.
我将在下面参考 C++14。
Template instantiations of std::array
are aggregates [array.overview]/2 . std::array
模板实例是聚合[array.overview]/2 。 Therefore, when initializing std::array
objects from a braced-init-list , aggregate-initialization will be performed indiscriminately of the number of initializers [dcl.init.list]/3.1 .因此,当从花括号初始化器列表初始化
std::array
对象时,聚合初始化将不加选择地执行初始化器[dcl.init.list]/3.1 的数量。 Other container classes cannot be aggregates because of the requirements for certain constructions (eg from a pair of iterators).由于某些结构的要求(例如来自一对迭代器),其他容器类不能聚合。
Aggregate-initialization initializes (potentially recursively) the data members from the initializers.聚合初始化从初始化器初始化(可能递归)数据成员。 In your case, it will try to initialize the first data member of
std::array<sf::Keyboard::Key, N>
from the initializer sequence
(which is of the same type).在您的情况下,它将尝试从初始化
sequence
(相同类型)初始化std::array<sf::Keyboard::Key, N>
的第一个数据成员。 For all implementations of std::array
I know, the first data member of std::array
is a C-style array.对于所有实施方式中
std::array
我知道,第一数据部件std::array
是一个C数组。 List-initialization will then try to initialize the first element of that array from the original initializer: sequence
.然后列表初始化将尝试从原始初始化
sequence
初始化该数组的第一个元素: sequence
。
Example:例子:
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`
The initialization in the last line will try to initialize ym[0]
from x
.最后一行中的初始化将尝试从
x
初始化ym[0]
。
CWG issue 1467 describes this and a related issue, list-initializing when there are no initializers. CWG 问题 1467描述了这个问题和一个相关问题,即在没有初始化程序时进行列表初始化。 The proposed resolution introduces a (yet another) special case for list-initialization that covers the issue in the OP.
提议的决议为列表初始化引入了一个(又一个)特殊情况,它涵盖了 OP 中的问题。 Quoting a recent github draft, [dcl.init.list]/3.1
引用最近的 github 草案,[dcl.init.list]/3.1
If
T
is a class type and the initializer list has a single element of type cvU
, whereU
isT
or a class derived fromT
, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).如果
T
是一个类类型并且初始化器列表有一个cvU
类型的元素,其中U
是T
或一个从T
派生的类,则从该元素初始化对象(通过复制列表初始化的复制初始化,或通过直接初始化直接列表初始化)。
Aggregate-initialization in recent drafts has lower "priority" (3.3), that is, will only be performed if the condition above is not met.最近草案中的聚合初始化具有较低的“优先级”(3.3),即只有在不满足上述条件时才会执行。
Recent versions of g++ (5.0) and clang++ (3.7.0) implement the proposed resolution even in C++11 mode.即使在 C++11 模式下,最新版本的 g++ (5.0) 和 clang++ (3.7.0) 也实现了建议的分辨率。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.