【问题标题】:Explicit specialization of function templates causes linker error函数模板的显式特化导致链接器错误
【发布时间】:2014-10-21 04:47:42
【问题描述】:

函数.h:

#pragma once
#include <iostream>

template<class T> void TemplatedFunction(T* p) {}

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

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

函数.cpp:

#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 文件包含许多 .cpp 文件所需的一些附加定义,则不能应用于复杂的项目。

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

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

编辑。 阅读前两个答案后:我在这里不问如何防止此类链接器错误。假设我无法将专业化移动到 .cpp 文件并将其保留在带有 staticinline 的 .h 文件中,当将这些函数添加到每个 .h文件是否包含在内,即使它们没有被使用?

【问题讨论】:

  • 显式特化的主体需要像普通的非模板函数(它们就是这样)一样放入 cpp 文件中。如果您愿意(这是有道理的),您可以交替使用inline 标记它们。

标签: c++ templates template-specialization


【解决方案1】:

所以,我看到专门的模板化函数的行为类似于非模板化函数。

正确。

在没有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 文件中时,这是否会导致代码重复和膨胀?

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

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

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

【讨论】:

    【解决方案2】:

    此类显式特化应移至 .cpp 文件或设为 inline。链接器会在那里找到它们。如果您在标头中定义它们,您将收到“已定义”错误消息,就像您在多个编译单元包含的标头中定义的普通非内联和非静态函数一样。

    【讨论】:

    • 谢谢,但我的问题的重点是:如果函数保留在 .h 文件中,这会导致优化构建中的代码膨胀吗?请参阅我编辑的问题。
    • 如果您将它们设为inline,请将这些特化视为常规内联函数。通常它们不会导致任何代码膨胀,但是 - 与常规内联一样 - 有时可能值得检查,例如将它们临时内联到 .cpp 并比较可执行文件的大小。
    • 谢谢,比较可执行文件的大小是个好主意,我会这样做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2013-11-04
    • 1970-01-01
    • 2019-11-30
    • 2012-12-14
    • 2010-12-11
    • 1970-01-01
    相关资源
    最近更新 更多