函数模板的显式专用化会导致链接器错误

Explicit specialization of function templates causes linker error

本文关键字:链接 错误 专用 函数模板      更新时间:2023-10-16

函数.h:

#pragma once
#include <iostream>
template<class T> void TemplatedFunction(T* p) {}
template<> void TemplatedFunction<float>(float* p) {}
template<> void TemplatedFunction<char>(char* p) {}

Functions.cp:

#include "Functions.h"
void Test()
{
    TemplatedFunction<float>(NULL);
    TemplatedFunction<char>(NULL);
}

main.cpp:

#include "Functions.h"
void Test();
int main()
{
    Test();
    return 0;
}

生成错误:

main.obj : error LNK2005: "void __cdecl TemplatedFunction<float>(float *)" (??$TemplatedFunction@M@@YAXPAM@Z) already defined in Functions.obj
main.obj : error LNK2005: "void __cdecl TemplatedFunction<char>(char *)" (??$TemplatedFunction@D@@YAXPAD@Z) already defined in Functions.obj

我知道两种解决方法:

  1. 不要将Functions.h包含在几个.cpp文件中-如果h-file包含许多.cpp文件所需的一些附加定义,则不能应用于复杂的项目中。

  2. 将所有模板化函数声明为static。但这意味着,专用函数会出现在包含functions.h的所有.cpp文件中,即使不使用它们,也可能导致代码重复。

因此,我看到专门的模板化函数的行为与非模板化函数类似。是否有其他解决方案可以在没有static声明的情况下防止链接器错误?如果函数被声明为static,那么如果不使用它们,现代C++编译器是否会将它们从优化构建中删除?

编辑在阅读了前两个答案后:我在这里不问如何防止这样的链接器错误。假设我不能将专用化移动到.cpp文件,并将其保留在带有staticinline的.h文件中,那么当这些函数被添加到包含.h文件的每个.cpp文件中时,即使不使用它们,这是否会导致优化构建中的代码重复和膨胀?

因此,我看到专门的模板化函数的行为与非模板化函数类似。

正确。

是否有其他解决方案可以在没有static声明的情况下防止链接器错误?

是的,像任何正常的非模板函数一样:

任一将函数专业化定义为inline

声明(但不定义)标头中的专业化:

template<> void TemplatedFunction<float>(float* p);
template<> void TemplatedFunction<char>(char* p);

并在Functions.cpp 中定义

template<> void TemplatedFunction<float>(float* p) {}
template<> void TemplatedFunction<char>(char* p) {}

这些是比使用static更好的选项,因为使函数静态还有其他副作用,例如在每个翻译单元中为函数提供不同的地址,以及使每个翻译单元的局部静态变量不同。这是一个语义变化,而不仅仅是链接器错误的解决方案。

如果函数被声明为static,那么如果不使用它们,现代C++编译器是否会将它们从优化构建中删除?

是的。但在任何使用它们的文件中,都会得到重复的代码,使可执行文件比函数的单个定义更大。

假设我不能将专业化移动到.cpp文件,并将其保留在带有static的.h文件中。。。

我看不出有什么好的理由需要这样做,但无论如何。。。

或者inline,当这些函数被添加到包含.h文件的每个.cpp文件中时,即使不使用它们,这是否会导致优化构建中的代码重复和膨胀?

不,如果它们没有在给定的文件中使用,它们将不会影响从该文件编译的对象的大小。

您的问题具有误导性,因为它似乎是关于模板的(标题非常清楚地是关于模板!),但未使用的内联/静态函数是否会导致代码膨胀与函数是否为模板无关。

如果你的问题只是"未使用的内联函数和静态函数会影响对象大小吗?"对于普通函数和函数模板,答案都是否定的。

此类明确的专业化应移动到.cpp文件或使其成为inline。链接器会在那里找到它们。如果在头中定义它们,则会得到"已定义"的错误消息,就像在由多个编译单元包含的头中定义的普通非内联和非静态函数中得到它们一样。