未定义对模板基类的成员函数的引用

Undefined reference to member function of template base class

提问人:αλεχολυτ 提问时间:1/29/2015 更新时间:1/29/2015 访问量:1878

问:

请考虑以下代码:

我的class.h:

template <class T>
struct S {
    void f();
};

struct MyClass : public S<int>
{
    void g();
};

我的类.cpp :

#include "myclass.h"
#include <iostream>

template <class T>
void S<T>::f()
{
    std::cout << "f()\n";
    /* some code here that could not be in header */
}

void MyClass::g()
{
    std::cout << "g()\n";
}

main.cpp :

#include "myclass.h"

int main()
{
    MyClass m;
    m.g();
    m.f(); // problem here
}

我有链接器错误:

对“S::f()”的未定义引用

我可以在不将 S::f() 的实现转移到头文件的情况下解决这个问题吗? 为什么当我声明从完整的专用模板基类派生的 MyClass 时没有实例化 S::f()?

C++ 模板 派生类 未定义引用

评论

1赞 molbdnilo 1/29/2015
为什么模板只能在头文件中实现?
0赞 Some programmer dude 1/29/2015
不应该在头文件中的代码,可以放在静态或全局(非模板化)函数中吗?或者使用例如疙瘩成语

答:

0赞 Mikhail Khorolets 1/29/2015 #1

如果不将 s::f() 函数的实现传输到头文件,就无法解决此问题。这是因为编译器在使用模板之前必须知道模板的实现。

1赞 WhozCraig 1/29/2015 #2

为什么当我声明从完整的专用模板基类派生的 MyClass 时没有实例化 S::f()?

因为您的 myclass.cpp 没有使用该模板,并且与翻译单元中所有未使用的模板一样,它们在生成的代码中没有任何内容。推导很好,如果使用,你会拉入该代码,生活会很好。但是你没有,所以你必须用另一种方式拉它......MyClass::g()S<T>::f()

您应该能够通过显式实例化来执行此操作。请注意 .cpp 文件中的以下添加内容:

#include "myclass.h"
#include <iostream>

template <class T>
void S<T>::f()
{
    std::cout << "f()\n";
}

void MyClass::g()
{
    std::cout << "g()\n";
}

template struct S<int>; // ADDED

但是,请注意。仅当唯一的用法是 时,这才有效。其他扩展将需要显式实例化的其他条目。S<int>

您也可以通过直接专业化来做到这一点,例如将 .cpp 更改为仅执行此操作:

#include "MyClass.h"
#include <iostream>

template <>
void S<int>::f()
{
    std::cout << "f()\n";
}

void MyClass::g()
{
    std::cout << "g()\n";
}

但在我看来,这将是相当有限的,因为您添加的每个附加类型都需要自己的专业化。

无论如何,祝你好运。

评论

0赞 αλεχολυτ 1/29/2015
谢谢。我尝试了显式实例化,但是在 f() 的实现之上进行的。当我向下移动它时 - 代码编译成功。
1赞 molbdnilo 1/29/2015 #3

添加显式实例化

template
struct S<int>;

到“myclass.cpp”使代码编译。

粗略地说,派生仅“实例化”类定义,而不是成员。
编译器无法在这一点上实例化,因为 的定义是未知的。
S<int>ff

您需要为正在使用的所有类型提供显式实例化,这在一定程度上限制了模板的实用性。

将模板定义排除在标头之外的一种流行方法是将它们放在自己的文件中,该文件位于标头末尾的 d。#include