如何打包,包括非移动可构造字段,可移动构造?

时间:2013-09-16 14:59:34

标签: c++ c++11

This是此问题的根源

使用clang ++ / libc ++和g ++ / libstdc ++编译以下代码时,我有不同的行为。

#include <type_traits>
#include <utility>
#include <iostream>

int main()
{
    using array_t = int[42];
    std::cout << "array_t:" << std::endl;
    std::cout << "    is_move_constructible: " << std::is_move_constructible<array_t>::value << std::endl;
    std::cout << "    is_move_assignable:    " << std::is_move_assignable<array_t>::value    << std::endl;
    std::cout << std::endl;

    using pair_t = std::pair<array_t, array_t>;
        std::cout << "pair_t:" << std::endl;
    std::cout << "    is_move_constructible: " << std::is_move_constructible<pair_t>::value << std::endl;
    std::cout << "    is_move_assignable:    " << std::is_move_assignable<pair_t>::value    << std::endl;
    std::cout << std::endl;

    pair_t p1;
    pair_t p2(std::move(p1));

    return 0;
}

铛(失败):

In file included from /home/soon/Src/C++/main/main.cpp:2:
/usr/include/c++/v1/utility:283:11: error: array initializer must be an initializer list
        : first(_VSTD::forward<first_type>(__p.first)),
          ^
/home/soon/Src/C++/main/main.cpp:20:12: note: in instantiation of member function 'std::__1::pair<int [42], int [42]>::pair' requested here
    pair_t p2(std::move(p1));
           ^
In file included from /home/soon/Src/C++/main/main.cpp:2:
/usr/include/c++/v1/utility:284:11: error: array initializer must be an initializer list
          second(_VSTD::forward<second_type>(__p.second))
          ^

g ++编译没有错误。输出是:

array_t:
    is_move_constructible: 0
    is_move_assignable:    0

pair_t:
    is_move_constructible: 1
    is_move_assignable:    1

我无法确定,哪个是正确的。我猜,如果一个类包含非移动可构造字段,则无法使用移动技术构造它。这是对的吗?

3 个答案:

答案 0 :(得分:1)

我不知道GCC(或者更确切地说是libstdc ++)是否正确允许此代码,但如果是,则结果是正确的。如果所有成员都有自己的移动构造函数,或者通常可以复制,则将生成默认的移动构造函数。 Pair的移动构造函数被指定为默认值,因此它遵循这些规则。它们的基元和数组都是可以复制的。

我怀疑libstdc ++是正确的,并且出于某种原因,你在libc ++中为_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS输入了编译器兼容性分支,它不支持数组,因为它不使用= default。您使用的是哪个版本的Clang,是否正确指定了-std=c++11

答案 1 :(得分:1)

我应该补充塞巴斯蒂安的答案,即clang-3.3用与gcc相同的结果(在运行时)编译你的代码没有问题。因此,您的clang编译器版本的错误行为似乎是一个错误,现在已经修复了。

答案 2 :(得分:1)

类型特征可能有点棘手。 is_move_constructible/assignable检查类型是否包含移动构造函数/赋值运算符(显式或隐式定义)。而已。那些类型特征将不会检测那些构造函数/运算符的实际实例是否形成不良。

由于std::pair包含移动构造函数/赋值运算符,因此is_move_constructibleis_move_assignable都将为std::true_type。这只表明它们已被定义,但这并不意味着您可以实际使用它们。

这已在this thread中讨论过。