#include <QFile>
#include <QString>
// this is some sort of low-level C function
void lowLevelOpenFD(int fd)
{
qDebug("Opened by fd: %d", fd);
}
// as well as this one
void lowLevelOpenName(const char *name)
{
qDebug("Opened by name: %s", name);
}
// this is a wrapper around low-level functions
template<typename FileId>
void callLowLevelOpen(FileId id);
template<>
void callLowLevelOpen(const QString &fileName)
{
lowLevelOpenName(QFile::encodeName(fileName).constData());
}
template<>
void callLowLevelOpen(int fd)
{
lowLevelOpenFD(fd);
}
// this is the function where the most stuff happens
template<typename FileId>
void openInternal(FileId id)
{
// lots of useful stuff goes here
// now we call one of the two low level functions
callLowLevelOpen(id);
// more useful stuff
}
// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal(name);
}
// this is high-level interface to the "open by FD" function
void openFile(int fd)
{
openInternal(fd);
}
int main()
{
openFile();
openFile(17);
return 0;
}
问题是上面的示例导致
error LNK2019: unresolved external symbol "void __cdecl callLowLevelOpen<class QString>(class QString)" (??$callLowLevelOpen@VQString@@@@YAXVQString@@@Z) referenced in function "void __cdecl openInternal<class QString>(class QString)" (??$openInternal@VQString@@@@YAXVQString@@@Z)
据我所知,这是因为编译器在从第一个高级重载中调用
openInternal<QString>()
时实例化了它。好的,所以我想到并修改了代码:// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal<const QString&>(name);
}
同样的问题。我以为我告诉编译器实例化
openInternal<const QString&>
,那么为什么它仍然抱怨<class QString>
?我也尝试过这个:// this is high-level interface to the "open by name" function
void openFile()
{
QString name = "file";
openInternal<const QString&>(static_cast<const QString&>(name));
}
现在,这看起来很愚蠢,但仍然无法正常工作。我不能明确地专门化
openInternal()
,因为它太大了,这种模板化困惑的关键是避免不必要的代码重复。我不能只重命名低级函数以将它们转换为重载函数,因为它们在第三方C库中。我唯一能做的就是将第一个callLowLevelOpen()
特化替换为template<>
void callLowLevelOpen(QString fileName)
{
lowLevelOpenName(QFile::encodeName(fileName).constData());
}
然后就可以了。实际上,性能损失几乎为零,因此这是一个完全有效的解决方法,但我只想了解这里发生的情况。
上面的代码只是一个SSCCE,如果有人感兴趣,实际的代码是there。这个特殊问题与
gzopen()/gzdopen()
,QuaGzipFilePrivate::open()
和QuaGzipFile::open()
函数有关。 最佳答案
由于您实际上更改了签名,因此我认为您实际上不想专门化函数模板,而是使用重载。这是使用std::string
的完整测试程序(如果可以在此重现问题,我不知何故只希望依赖于标准类):
#include <string>
template <typename T> void f(T);
// #define BROKEN
#if defined(BROKEN)
template <> void f(std::string const&) {}
#else
void f(std::string const&) {}
#endif
int main()
{
std::string s;
f(s);
}
如果您在此代码中使用
#defined BROKEN
,它将无法正常工作。出现这种情况的原因是,编译器根据主模板选择重载。这将永远不会添加
const&
部分。完成此操作后,编译器将寻找所选重载的潜在特长。由于这永远不会推导用于特化的符号,因此不会被采用。为何
f<std::string const&>(s)
没有选择专业?对我来说,尝试同时使用gcc和clang。关于c++ - const QString&的显式模板特化导致 Unresolved external ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9054942/