0

是这个问题的根源

在使用 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

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

4

3 回答 3

1

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

我怀疑 libstdc++ 是正确的,并且由于某种原因,您正在进入 libc++ for 中的编译器兼容性分支_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS,它不支持数组,因为它不使用= default. 您使用的是什么版本的 Clang,您是否正确指定-std=c++11

于 2013-09-16T15:05:04.033 回答
1

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

于 2013-09-16T15:12:02.543 回答
1

类型特征可能有点棘手。is_move_constructible/assignable检查类型是否包含移动构造函数/赋值运算符(显式或隐式定义)。而已。这些类型特征不会检测到这些构造函数/操作符的实际实例化是否格式错误。

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

这已在此线程中讨论过。

于 2013-09-16T15:19:17.593 回答