所有 CopyConstructible 类型都是 MoveConstructible 类型吗?

问题描述 投票:0回答:3

根据工作草案N3337(与已发布的ISOC++11标准最相似的草案)和cppreference.com,答案是肯定的。

N3337:

表 21 — 可复制构造的要求(除了 可移动构造)[可复制构造] [...]

cppreference.com

类型 T 满足 CopyConstructible if

  • 类型 T 满足 MoveConstructible,并且 [...]

但是根据在 Ubuntu 14.04.3 LTS 中使用 gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 编译 main.cpp 并使用引用语句运行 a.out 的结果,答案是否定的。

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;
}

从终端编译并运行:

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

结果(输出):

0
1

我是否误解了什么,或者 N3337 和 cppreference.com 错误,或者 gcc 是否包含错误?

c++ c++11 ubuntu gcc
3个回答
13
投票

std::is_copy_constructible<T>
被定义为完全
std::is_constructible<T, const T&>
,即它仅测试从 const 左值构造是否可能,它不测试 CopyConstructible 概念的所有属性。

所以你的测试并没有显示你认为它显示的内容。您的类型不是 CopyConstructible 类型,因为它不满足其他一些要求。

对于原来的问题,是的。因为所有 CopyConstructible 类型都必须满足 MoveConstructible 的要求,所以它们都是 MoveConstructible 类型。 MoveConstructible 不要求移动任何内容,只需要从右值进行构造是可能的,并且所有 CopyConstructible 类型都可以从右值构造(即使它们可能会进行深层复制而不是移动)。

您可以创建可从左值复制但不能从右值复制的反常类型,或者可以从 const 左值复制但不能从非 const 左值复制,以及其他令人厌恶的行为。此类类型不可复制构造,并且不能很好地与 C++ 标准库配合使用。很少有充分的理由去创造这样的反常类型。


7
投票

你的例子有点误导你。

As(As&&)=delete;

通过删除移动构造函数,使用

As
构造
As&&
变得非法,尽管可以调用复制构造函数,因为它采用了对 const 的引用。

显示您正在寻找的行为的示例如下:

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

我刚刚删除了移动构造函数的删除。

As
不会隐式声明移动构造函数,因为它有一堆其他用户声明的特殊函数*。如果您在此示例上运行测试,您将看到该类是可移动构造的,即使它没有移动构造函数。

现场演示


*具体来说,如果存在用户声明的复制构造函数、复制赋值运算符、移动赋值运算符或析构函数,则不会隐式声明移动构造函数。


2
投票

is_copy_constructible
不要求文字可移动。当它说

可复制构造要求(除了可移动构造之外)[可复制构造]

这意味着要成为 CopyConstructible,该类必须满足 MoveConstructible 的要求,即

T u = rv;       u is equivalent to the value of rv before the construction
T(rv)           T(rv) is equivalent to the value of rv before the construction

rv’s state is unspecified. [ Note: rv must still meet the requirements of the
library component that is using it. The operations listed in those requirements
must work as specified whether rv has been moved from or not. — end note ]

除了[可复制构造]

T u = v;        the value of v is unchanged and is equivalent to u
T(v)            the value of v is unchanged and is equivalent to T(v)

std::is_move_constructible<As>::value
为假的原因是您删除了禁止移动构造的移动构造函数。需要有一个未删除的移动构造函数并满足 [moveconstructible] 才能为真。

© www.soinside.com 2019 - 2024. All rights reserved.