Search code examples
c++c++11ubuntugcc

Are all CopyConstructible types MoveConstructible types?


According to the working draft N3337 (the most similar draft to the published ISOC++11 standard) and cppreference.com, the answer is yes.

N3337:

Table 21 — CopyConstructible requirements (in addition to MoveConstructible) [copyconstructible] [...]

cppreference.com:

The type T satisfies CopyConstructible if

  • The type T satisfies MoveConstructible, and [...]

But according to the result of compiling main.cpp with gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 and running a.out with the quoted statements in Ubuntu 14.04.3 LTS, the answer is not.

main.cpp:

#include <iostream>
#include <type_traits>

struct As
{
    As()=default;
    As(As&&)=delete;
    As(const As&)=default;
    As& operator=(As&&)=delete;
    As& operator=(const As&)=delete;
    ~As()=default;
};

int main()
{
    std::cout<<std::is_move_constructible<As>::value<<std::endl;
    std::cout<<std::is_copy_constructible<As>::value<<std::endl;

    return 0;
}

compiling and running from terminal:

$ g++ -std=c++11 main.cpp
$ ./a.out

the result (output):

0
1

Did I misunderstand something or is N3337 and cppreference.com wrong, or does gcc contains a bug?


Solution

  • std::is_copy_constructible<T> is defined to be exactly std::is_constructible<T, const T&> i.e. it only tests that construction from a const lvalue is possible, it doesn't test all the properties of the CopyConstructible concept.

    So your test does not show what you think it shows. Your type is not a CopyConstructible type, because it fails some of the other requirements.

    As for the original question, yes. Because all CopyConstructible types must meet the requirements for MoveConstructible they are all MoveConstructible types. MoveConstructible doesn't require that anything gets moved, only that construction from rvalues is possible, and all CopyConstructible types can be constructed from rvalues (even if they might do a deep copy not a move).

    You can create perverse types that can be copied from lvalues but not from rvalues, or can be copied from const lvalues but not non-const lvalues, and other abominations. Such types are not CopyConstructible, and do not work well with the C++ standard library. There are very few good reasons to ever create perverse types like that.