考虑以下最小的例子,在更大的项目中再现问题:

spec.h:
#include <iostream>

class A
{
public:
    template<typename T>
    T test(const std::string& a)
    {
        std::cout << "DEFAULT CALLED WITH " << a << "\n";
        return T();
    }
};
.

其他.cpp:
#include "spec.h"

template<>
float A::test<float>(const std::string& a)
{
    std::cout << "SPECIAL CALLED WITH " << a << "\n";
    return float();
}
.

spec.cpp:
#include <iostream>
#include "spec.h"

int main()
{
    A a;
    a.test<int>("int");
    a.test<float>("float");
    return 0;
}
.

编译:
$ make
rm -f *.o lib.a output
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
ar cr lib.a other.o
clang++ -g -o output lib.a spec.o
rm -f *.o output2
clang++ -g other.cpp -c
clang++ -g spec.cpp -c
clang++ -g -o output2 other.o spec.o

$ ./output
DEFAULT CALLED WITH int
DEFAULT CALLED WITH float

$ ./output2
DEFAULT CALLED WITH int
SPECIAL CALLED WITH float
.

问题:

为什么发生这种情况?它是否被剥离了?lib.a和direct对象文件使用情况有什么区别?: - )

谢谢!

有帮助吗?

解决方案

从第14.7.3p6:

如果模板,成员模板或类模板的成员明确地专门化,则在首次使用该专业化之前,应在每个翻译单元中宣布将在第一次使用隐含实例化的专业化之前宣布其中发生这种使用发生;不需要诊断。如果程序不提供显式专业化的定义,并且以造成隐含实例化的方式使用专业化或者成员是虚拟成员函数的方式,则该程序不起作用,无需诊断。

您的程序没有成立,因为您使用spec.cpp的专业化而不首先在该翻译单元中首先声明。或者,正如以下段落所说:

函数模板的显式专业化声明的位置,类模板,类模板的成员函数,类模板的静态数据成员,类模板的成员类,类模板的成员枚举,类模板的成员枚举,类模板的成员类模板,成员函数类模板的模板,类模板成员模板的成员函数,非模板类的成员模板的成员函数,成员函数模板的成员类模板等级等级的班级模板的部分专业化声明的位置非模板类的类模板,类模板的成员类模板等,可以影响程序是否在上面指定的翻译单元中的显式专业化声明及其实例中的相对定位良好地形成。下面。

在写一个专业化时
要小心它的位置;
或使它汇编
如此试验
点击它的自我牺牲。

作为作为最棒的<罢工>段落 limerick在整个标准

其他提示

本voigt的答案是正确的,但我想为它添加一点。

您基本上是函数的两个不同版本,一个换句话说.O和一个以spec.o(由内联模板生成)。链接器旨在选择一个且只有一个,假设它们都与标准所需的相同。在第一种情况下,如果符号尚未定义,链接器将仅从库中提取定义。由于它在spec.o中定义了库定义。

在标题中的定义每个翻译单元可以创建自己的实例化。因此,从来没有引用你的专业版本的未定义符号。相应地,在查看库时不包含具有专门版本的对象文件:它不会定义任何未定义的符号。当链接时明确地包括对象文件时,链接器没有比包含它的选择。但是,您需要声明所有专业化:如果没有声明,编译器没有Clue常规版本不适用。发生这种版本,无论是否使用它,从而都取决于符号被处理的方式。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top