具有显式模板实例化的未解析外部文件。声明语法是什么?

Unresolved externals with explicit template instantiations. What is the declaration syntax?

提问人:Rhubbarb 提问时间:3/23/2010 更新时间:5/22/2012 访问量:1566

问:

这里有一些简化的代码来演示我遇到的问题。

我有一个模板函数,我只想编译某些固定的实例化。

函数声明如下:

// *** template.h ***
int square (int x);
double square (double x);

定义如下:

// *** template.cpp ***
#include "template.h"

// (template definition unusually in a code rather than header file)
template <typename T>
T square (T x)
{
    return x*x;
}

// explicit instantiations
template int square (int x);
template float square (float x);

而且,一个示例用法是:

// *** main.cpp ***

#include <iostream>
using namespace std;

#include "template.h"

int main (void)
{
    cout << square(2) << endl;
    cout << square(2.5) << endl;
}

尝试编译此会导致链接错误,大致如下:

main.obj:函数 main 中引用的未解析外部符号“int square(int)”

我明白问题出在哪里:我的显式模板实例化的函数签名与头文件中的函数签名不匹配。

请问显式模板实例的(前向)声明的语法是什么?我不想转发声明模板定义,也不想将模板定义移动到头文件中。

值得一提的是,我确实有一个解决方法,即使用包装函数,将以下内容添加到上述文件中:

// *** template.cpp ***

// ...

// wrap them [optionally also inline the templates]
int square (int x) { return square<> (x); }
double square (double x) { return square<> (x); }

这将按预期进行编译和工作。然而,这对我来说似乎是一个黑客。在 C++ 和模板语法中应该有比这更优雅的东西。

任何帮助或提示将不胜感激。

C++ 模板 实例化 未解析外部

评论


答:

5赞 James McNellis 3/23/2010 #1

您需要在标头中声明函数模板:

template <typename T>
T square(T x);

正如您现在所拥有的那样,您在标头中声明了两个非模板函数,它们从未定义过。

评论

1赞 Ronny Brendel 3/24/2010
但这表明您有更多的类型可用,而不仅仅是 double 和 int
0赞 James McNellis 3/24/2010
@Ronny:如果尝试使用在源文件中提供显式实例化以外的任何类型实例化模板,则编译将失败。如果从声明中看不出来,最好记录函数模板,以详细说明可以使用哪些类型实例化它。
0赞 Ronny Brendel 3/24/2010
不同的源文件(main.cpp)+标头如何知道显式实例化?链接时,您会收到一个错误 - 可能不是很有帮助。
2赞 Georg Fritzsche 3/24/2010
您可以使用描述性静态断言来定义模板函数 - 这样错误就不会延迟到链接阶段。
1赞 Rhubbarb 3/24/2010
感谢您到目前为止的评论,但请注意,我的问题不是关于一般的模板函数,而是关于显式模板函数实例化的问题。(举个例子,虽然在我的例子中不相关,但这些函数可能在库中提供,但不会被调用;显式实例化会强制编译器生成所需的代码。我不希望在标头中声明模板,因为该模板仅在特定的源文件中定义(它是“伪私有”)。
1赞 David Lin 5/22/2012 #2

如果要从头文件中隐藏模板,则没有其他方法。你必须有包装函数,因为它没有与 mangling 相同的名称,并且 C++ 没有为你提供改变它的方法。int square (int x);template int square (int x);

可以作为示例查看名称混合在 Visual Studio 中的不同之处