#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, реальный код там , если кому-то интересно. Эта конкретная проблема связана с функциями gzopen()/gzdopen()
, QuaGzipFilePrivate::open()
и QuaGzipFile::open()
.