Reputation: 33651
This is the root of this question
I have different behavior while compiling the following code with clang++/libc++ and 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;
}
clang(fails):
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++ compiles without errors. The output is:
array_t:
is_move_constructible: 0
is_move_assignable: 0
pair_t:
is_move_constructible: 1
is_move_assignable: 1
I can't determine, which is correct. As I guess, if a class contains non-move-constructible field, it can't be constructed using move technique. Is that correct?
Upvotes: 0
Views: 226
Reputation: 21900
Type traits can be kind of tricky. is_move_constructible/assignable
check whether a type contains a move constructor/assignment operator(either explicitly or implicitly defined). That's it. Those type traits won't detect if the actual instantiation of those constructors/operators is ill formed.
Since std::pair
contains a move constructor/assignment operator, then both is_move_constructible
and is_move_assignable
will be std::true_type
. That only indicates that they're defined, but that doesn't mean that you can actually use them.
This has been discussed in this thread.
Upvotes: 1
Reputation: 45414
I should add to Sebastian's answer that clang-3.3 compiles your code w/o problems with the same result (at run-time) as gcc. So the misbehaviour of your version of the clang compiler appears to be a bug, that has been fixed by now.
Upvotes: 1
Reputation: 71899
I don't know whether GCC (or rather libstdc++) is right in allowing this code, but if it is, then the result is correct. The default move constructor will be generated iff all members either have their own move constructor, or are trivially copyable. Pair's move constructor is specified to be defaulted, so it follows these rules. Primitives and arrays of them are trivially copyable.
I suspect that libstdc++ is right, and for some reason you're entering the compiler compatibility branch in libc++ for _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS
, which doesn't support arrays because it doesn't use = default
. What version of Clang are you using, and are you correctly specifying -std=c++11
?
Upvotes: 1