外部模板类std::可移动对象的容器
extern template class std::container of movable objects
我想使用新的c++ 11功能'extern模板类'与stl容器的可移动对象(不可复制),并得到编译器错误。
的例子:MyFile.hpp
#pragma once
#include <cstdio>
class MyFile
{
std::FILE * handle;
public:
MyFile(const char * filename);
~MyFile();
MyFile(MyFile && that);
MyFile & operator=(MyFile && that);
MyFile(const MyFile&) = delete;
void operator=(const MyFile&) = delete;
std::FILE const * getFile() const;
};
MyFile.cpp
:
#include "MyFile.hpp"
#include <iostream>
MyFile::MyFile(const char * filename)
: handle{nullptr}
{
if (!(handle = fopen(filename, "r")))
throw std::runtime_error("blah blah blah");
}
MyFile::~MyFile()
{
std::cout << "File::~File()" << std::endl;
if (handle)
fclose(handle);
}
MyFile::MyFile(MyFile && that)
: handle{nullptr}
{
*this = std::move(that);
}
MyFile & MyFile::operator =(MyFile && that)
{
std::swap(handle, that.handle);
return *this;
}
const std::FILE * MyFile::getFile() const
{
return handle;
}
FileDeque.hpp
:
#pragma once
#include <deque>
#include "MyFile.hpp"
extern template class std::deque<MyFile>;
using FileDeque = std::deque<MyFile>;
FileDeque.cpp
:
#include "FileDeque.hpp"
template class std::deque<MyFile>;
,测试程序:# include
using namespace std;
#include "MyFile.hpp"
#include "FileDeque.hpp"
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
使用Visual Studio 2013,我得到以下错误:
D:WinProgramsMicrosoft Visual Studio 12.0VCINCLUDEdeque(1714):错误C2280: 'MyFile::MyFile(const MyFile &)':试图引用已删除的函数
d:develunique_ptr3MyFile.hpp(18):查看声明'MyFile::MyFile'
D:WinProgramsMicrosoft Visual Studio 12.0VCINCLUDEdeque(1682):在编译类模板成员函数'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)'时与[_Ty = MyFile)
D:WinProgramsMicrosoft Visual Studio 12.0VCINCLUDEdeque(1510):参考函数模板实例化'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)'正在编译与[_Ty = MyFile)
d:develunique_ptr3 filedequeue .hpp(7):参见编译类模板实例化` std::deque> `的参考与[_Ty = MyFile)
生成代码…
很明显,编译器试图实例化std::deque>::_Insert_n函数,该函数使用对象复制,但为什么?
如果std::deque直接在main.cpp中使用,则不会出现错误:
#include <iostream>
#include <deque>
using namespace std;
#include "MyFile.hpp"
using FileDeque = std::deque<MyFile>;
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
也尝试了clang和gcc,得到类似的错误。
我的问题是:
- 是否有可能使编译器不实例化容器的可移动对象类?为什么编译器试图实例化需要复制支持的方法?
- 我想错了吗?
c++ 11 (temp.explicit)/8个州:
命名类模板专门化的显式实例化也是其每个成员(不包括从基类继承的成员)的同类(声明或定义)的显式实例化,这些成员之前没有在包含显式实例化的翻译单元中显式专门化,除非如下所述。
由于std::deque<foo>
的一些成员需要可复制类型foo
(至少是复制构造函数),因此实例化它们是病态的。这就是你观察到的错误的原因。
// in FileDeque.hpp:
// Uncomment this to get linker errors suggesting
// other members to explicitly instantiate:
// extern template class std::deque<MyFile>;
extern template std::deque<MyFile>::deque();
extern template std::deque<MyFile>::~deque();
extern template auto std::deque<MyFile>::begin() -> iterator;
extern template auto std::deque<MyFile>::end() -> iterator;
// ...
// in FileDeque.cpp:
template std::deque<MyFile>::deque();
template std::deque<MyFile>::~deque();
template auto std::deque<MyFile>::begin() -> iterator;
template auto std::deque<MyFile>::end() -> iterator;
// ...
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么协程的返回类型必须是可移动构造的?
- 我应该使我的局部变量常量还是可移动的
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 如何获取类型是否真正可移动可构造
- 可移动但不可复制的对象:按值传递还是按引用传递?
- 对于可移动类型,按值传递比重载函数更好吗?
- 使用参数将仅可移动对象捕获到 lambda
- 从从可调用参数创建的线程对象参数移动构造 C++11 线程
- C++11/VS2010:返回包含不可复制但可移动对象的容器
- 传递可移动对象
- 无法将可移动对象与Boost.Asio一起使用
- 如何按值返回一个不可复制的、可移动的对象作为const并存储它
- 在std::函数中存储不可复制但可移动的对象
- 在std::pair中存储不可复制(但可移动)的对象
- Boost序列化不可复制但可移动的对象
- 包含boost::可选对象的std::矢量对象是否可以移动?可移动助推::可选
- 编译器是否在最后一次使用可移动对象时自动使用移动语义?
- 外部模板类std::可移动对象的容器
- 作用于可移动但不可复制对象序列的变化STL算法的行为