C++ 包含不可移动构造字段的类型如何可以移动构造?

C++ 包含不可移动构造字段的类型如何可以移动构造?,c++,c++11,C++,C++11,这是问题的根源 在使用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 <

这是问题的根源

在使用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;
}
我不能确定哪一个是正确的。我猜,如果一个类包含不可移动的可构造字段,那么它就不能使用移动技术来构造。这是正确的吗?

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

我怀疑libstdc++是正确的,出于某种原因,您正在libc++中为
\u LIBCPP\u输入编译器兼容性分支,它没有默认的函数
,不支持数组,因为它不使用
=default
。您使用的是什么版本的Clang,您是否正确地指定了
-std=c++11

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


我怀疑libstdc++是正确的,出于某种原因,您正在libc++中为
\u LIBCPP\u输入编译器兼容性分支,它没有默认的函数
,不支持数组,因为它不使用
=default
。您使用的是什么版本的Clang,并且您是否正确指定了
-std=c++11

我应该在Sebastian的回答中补充一点,即Clang-3.3编译代码时不会出现与gcc相同的问题(在运行时)。因此,您版本的clang编译器的错误行为似乎是一个bug,现在已经修复。

我应该补充Sebastian的回答,clang-3.3编译代码时没有出现与gcc相同的问题(在运行时)。因此,您版本的clang编译器的错误行为似乎是一个bug,目前已经修复。

类型特征可能有点棘手<代码>是否可移动\u可构造/可赋值检查类型是否包含移动构造函数/赋值运算符(显式或隐式定义)。就这样。这些类型特征不会检测这些构造函数/运算符的实际实例化是否格式错误

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


这已经在中讨论过了。

类型特征可能有点棘手<代码>是否可移动\u可构造/可赋值
检查类型是否包含移动构造函数/赋值运算符(显式或隐式定义)。就这样。这些类型特征不会检测这些构造函数/运算符的实际实例化是否格式错误

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


这已经在中讨论过。

您确定要用
libc++
编译它吗?因为我也有clang++3.3。@很快clang版本3.3(tags/RELEASE_33/final)和主干libc++的尖端,所以,如果它真的被修复了,我不会在bugtracker中打开票据。谢谢你提供的信息。你确定是用
libc++
编译的吗?因为我也有clang++3.3。@很快clang版本3.3(tags/RELEASE_33/final)和主干libc++的尖端,所以,如果它真的被修复了,我不会在bugtracker中打开票据。谢谢你提供的信息。我正在使用clang++3.3。是的,我确信,我正确地使用了
-std=c++11
。现在我正在研究关于默认移动构造函数的标准要求。一旦我发现你的答案是正确的,我会接受你的答案。试试12.8/9-11的规则。特别是11的最后一个项目,我使用的是clang++3.3。是的,我确信,我正确地使用了
-std=c++11
。现在我正在研究关于默认移动构造函数的标准要求。一旦我发现你的答案是正确的,我会接受你的答案。试试12.8/9-11的规则。特别是11的最后一个项目符号。如果参数是
pair&&
,则必须调用
std::pair
的移动构造函数,不是吗?@很快是的,仅当该参数是xvalue或prvalue时。看,但在我的代码中“我实际使用它们”。查看
配对p2(std::move(p1))。还是我误解了你?@很快,是的,你在用它。这就是它崩溃的原因
std::pair
有一个移动构造函数,但是为
std::pair
实例化它不起作用,因为
array\u t
是不可移动的。但是它只有在使用libc++时才会崩溃。将clang或gcc与libstdc++一起使用不会产生错误。如果参数是
pair\t&&
,则必须调用
std::pair
的移动构造函数,不是吗?@很快是的,仅当该参数是xvalue或prvalue时。看,但在我的代码中“我实际使用它们”。查看
配对p2(std::move(p1))。还是我误解了你?@很快,是的,你在用它。这就是它崩溃的原因
std::pair
有一个移动构造函数,但是为
std::pair
实例化它不起作用,因为
array\u t
是不可移动的。但是它只有在使用libc++时才会崩溃。将clang或gcc与libstdc++一起使用不会产生错误。
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))
          ^
array_t:
    is_move_constructible: 0
    is_move_assignable:    0

pair_t:
    is_move_constructible: 1
    is_move_assignable:    1