0

我有一个类Base in base.h,它有一个模板函数

class Base {
 template <typename T> void test(T a);
}

这个模板应该读入intdouble输入,我有类Derived,它是从类Base派生的

我试图在派生类中调用函数测试,但出现链接器错误。

最后,我意识到如果在base.cpp,我添加

void test(int a);
void test(double a);

不会有编译器错误。这个解决方案看起来很尴尬,有没有更好的解决方案?谢谢

4

3 回答 3

3

C++ 模板必须在使用它们的同一翻译单元(.CPP 文件加上所有包含的头文件)中定义(给定完整的函数体)。在您的头文件中,您所做的一切都是声明(给定名称和签名)函数。结果是,当您包含 时base.h,编译器看到的所有内容是:

class Base {
  template <typename T> void test(T a);
}

这声明但不定义函数。要定义它,您必须包含一个函数体:

class Base {
  template <typename T> void test(T a)
  {
    // do something cool with a here
  }
}

之所以需要这样做,是因为 C++ 编译器“按需”为模板生成代码。例如,如果您调用:

Base obj;
obj.test< int >( 1 );
obj.test< char >( 'c' );

Base::test编译器会根据模板生成两组机器码,一组用于 a int,一组用于 a char。这里的限制是Base::test模板的定义必须在同一个翻译单元(.CPP 文件)中,否则编译器将不知道如何为每个版本的Base::test函数构建机器代码。编译器一次只对一个翻译单元进行操作,因此它不知道您是否Base::test< T >在其他一些 CPP 文件中进行了定义。它只能与手头的东西一起工作。

这与泛型在 C#、Java 和类似语言中的工作方式完全不同。就我个人而言,我喜欢将模板视为由编译器根据需要扩展的文本宏。这迫使我记住,模板函数的完整主体需要包含在使用它的任何 CPP 文件中。

于 2011-09-29T07:02:45.990 回答
2

您必须完全定义模板函数test才能使用它。最简单的方法就是将你的函数体写在标题中base.h

class Base {
 template <typename T> void test(T a)
 {
    ... function body here
 }
}
于 2011-09-29T06:30:40.123 回答
0

如果您在基类中声明模板函数,这意味着它在编译时采用模板参数,但是如果您尝试通过作为运行时实现的派生类访问,那么您在运行时提供的模板请求在编译时是不可能的,主要是 c++不支持这个。

于 2012-10-19T11:36:12.167 回答