我想将新的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:\ WinPrograms \ Microsoft Visual Studio 12.0 \ VC \ INCLUDE \ deque(1714):错误C2280:'MyFile :: MyFile(const MyFile&amp;)':尝试引用已删除的函数
d:\ devel \ unique_ptr3 \ MyFile.hpp(18):参见'MyFile :: MyFile'的声明
D:\ WinPrograms \ Microsoft Visual Studio 12.0 \ VC \ INCLUDE \ deque(1682):编译类模板成员函数'void std :: deque&gt; :: _ Insert_n(std :: _ Deque_const_iterator&gt;&gt;,unsigned int, const MyFile&amp;)' 同 [ _Ty = MyFile的 ]
D:\ WinPrograms \ Microsoft Visual Studio 12.0 \ VC \ INCLUDE \ deque(1510):参见函数模板实例化'void std :: deque&gt; :: _ Insert_n(std :: _ Deque_const_iterator&gt;&gt ;, unsigned int, const MyFile&amp;)'正在编译中 同 [ _Ty = MyFile的 ]
d:\ devel \ unique_ptr3 \ FileDeque.hpp(7):请参阅类模板实例化'std :: deque&gt;'被编译 同 [ _Ty = MyFile的 ]
生成代码......
很明显,编译器试图实例化使用对象复制的std :: deque&gt; :: _ Insert_n函数,但为什么呢?
如果在main.cpp中直接使用std :: deque,我就不会出错:
#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并获得类似的错误。
所以我的问题:
答案 0 :(得分:5)
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;
// ...