简体   繁体   English

c ++ 11数组初始化不会调用复制构造函数

[英]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 cv U , where U is T or a class derived from T , the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).如果T是一个类类型并且初始化器列表有一个cv U类型的元素,其中UT或一个从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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM