【发布时间】:2014-04-18 08:50:01
【问题描述】:
我想将新的 C++11 功能“外部模板类”与可移动对象的 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>;
还有测试程序: #包括
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 &)' : 试图引用已删除的函数
d:\devel\unique_ptr3\MyFile.hpp(18) : 参见 'MyFile::MyFile' 的声明
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1682) : 在编译类模板成员函数 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const我的文件 &)' 和 [ _Ty=我的文件 ]
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1510) :参见对函数模板实例化的参考 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)' 正在编译 和 [ _Ty=我的文件 ]
d:\devel\unique_ptr3\FileDeque.hpp(7) : 请参阅对正在编译的类模板实例化 'std::deque>' 的引用 和 [ _Ty=我的文件 ]
生成代码...
很明显,编译器试图实例化使用对象复制的 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 并得到类似的错误。
所以我的问题:
- 是否可以让编译器不实例化容器的可移动对象类?为什么编译器会尝试实例化需要复制支持的方法?
- 我想错了吗?
【问题讨论】:
-
这不是外部模板的问题,而是显式实例化的问题。尝试将字符串
template class std::deque<MyFile>;添加到 main 函数的第二个变体中。事实上,我认为内部函数_Insert_n使用了复制构造函数。它不会出现在第二种情况下,因为隐式实例化不会实例化所有类模板成员(仅实例化那些真正使用的成员)。 -
类模板的显式实例化实例化所有成员,无论格式是否正确。您必须仅显式实例化为您的参数格式正确的成员。
-
@Constructor:这就是问题所在,即我不希望 std::deque
在不同的翻译单元中多次实例化。 -
@Casey 是标准的要求还是实现的错误?您能否提供标准的摘录。
-
这不是错误。有关详细信息,请参阅第 [temp.explicit] 14.7.2/8 和 14.7.2/9 段。
标签: c++ templates c++11 stl visual-studio-2013