根据N3337工作草案(与已发布的ISOC ++ 11标准最相似的草案)和cppreference.com,答案是肯定的。
N3337:
表21 - CopyConstructible要求(除了 MoveConstructible)[copyconstructible] [...]
如果
,则类型T满足CopyConstructible
- 类型T满足MoveConstructible和[...]
但是根据使用gcc(Ubuntu 4.8.4-2ubuntu1~14.04)4.8.4编译main.cpp并在Ubuntu 14.04.3 LTS中使用引用语句运行a.out的结果,答案不是。< / p>
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是否包含错误?
答案 0 :(得分:12)
std::is_copy_constructible<T>
被定义为std::is_constructible<T, const T&>
,即它只测试来自const lvalue的构造,它不会测试CopyConstructible概念的所有属性。
因此,您的测试不会显示您认为它显示的内容。您的类型不是CopyConstructible类型,因为它无法满足其他一些要求。
至于原来的问题,是的。因为所有CopyConstructible类型必须满足MoveConstructible的要求,所以它们都是MoveConstructible类型。 MoveConstructible并不要求任何东西被移动,只有来自rvalues的构造是可能的,并且所有CopyConstructible类型都可以从rvalues构建(即使它们可能做深拷贝而不是移动)。
您可以创建可以从左值复制但不能从右值复制的反常类型,或者可以从常量值复制但不能复制非常量左值和其他可憎值。这些类型不是CopyConstructible,并且不适用于C ++标准库。创造这样的反常类型的原因很少。
答案 1 :(得分:7)
你的例子在某种程度上误导了你。
As(As&&)=delete;
通过删除移动构造函数,使用As
构造As&&
是非法的,即使可以调用复制构造函数,因为它采用了引用到const。 / p>
显示您要查找的行为的示例如下:
struct As
{
As()=default;
As(const As&)=default;
As& operator=(As&&)=delete;
As& operator=(const As&)=delete;
~As()=default;
};
我刚删除了移动构造函数的删除。 As
将没有隐式声明的移动构造函数,因为它有一堆其他用户声明的特殊函数*。如果您在此示例中运行测试,即使它没有移动构造函数,您也会看到该类是可构造的。
*特别是,如果有用户声明的复制构造函数,复制赋值运算符,移动赋值运算符或析构函数,则不会隐式声明移动构造函数。
答案 2 :(得分:2)
is_copy_constructible
并不要求该类型可移动。什么时候说
CopyConstructible要求(除MoveConstructible外)[copyconstructible]
这意味着要成为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 ]
除了[copyconstructible]
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]是必需的。