【发布时间】:2018-12-14 14:03:27
【问题描述】:
我这里有代码:
#include <string>
#include <iostream>
#include <initializer_list>
template <typename T>
class Test
{
public:
Test(std::initializer_list<T> l)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test(const Test<T>& copy)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test(Test&&) = delete;
Test() = delete;
};
void f(const Test<Test<std::string>>& x)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void f(const Test<std::string>& x)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
f(Test<Test<std::string>>{x});
}
int main()
{
Test<std::string> t1 {"lol"};
f(t1);
return 0;
}
我尝试在我的 linux mint 19 上使用 GCC 7.3.0 使用以下命令进行编译:
g++ -std=c++11 -O0 test.cpp -o test -Wall -pedantic
编译失败,错误提示:
f(Test<Test<std::string>>{x});
需要移动构造函数,但它已被删除。我一直认为移动和复制构造函数在编译方面是等价的,因为右值可以绑定到 const 引用,但是显式定义的右值引用的重载只是在重载决议中优先考虑。这是我第一次看到编译器实际上需要移动构造函数并且不会只使用复制。为什么?我错过了什么吗?
【问题讨论】:
-
一个
deleted 函数被声明。它将在名称查找期间包含在重载集中,因此您实际上是在尝试调用deleted 函数。如果您定义了一个复制构造函数并且根本没有声明一个移动构造函数,那么您将获得您所期望的行为。 -
@BoBTFish 在这种情况下,我的类将定义移动,因为编译器将为我生成它,我将拥有一个。使用 delete 我禁止编译器生成一个。
-
如果您有一个用户定义的复制构造函数,这将禁止编译器提供移动构造函数。 See this table.
标签: c++ c++11 copy-constructor move-constructor