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