在派生类中的头文件中定义模板,在cpp文件中进行定义。

3

可能有重复:
为什么模板类的实现和声明应该在同一个头文件中?

我试图在头文件中定义一个模板,然后在cpp文件中定义它,并且模板应该在派生类内部定义。以下是我的代码:

头文件:

#ifndef  ........
#define .....
 template <class mytypename>
 class abcBaseClass:public abcDerivedClass{
 public:
     mytypename getvalue(char*)
};
#endif


源文件:

mytypename abcDerivedClass<mytypename>::getvalue(char* name){

}

我只是想知道这样做是否正确?

我想要实现的是... 我最终想要进行调用的方式是

double x = a->getvalue<double>(char)

实现必须与声明在同一文件中,除非您明确实例化类型。此外,“typename”是一个保留字。 - Seth Carnegie
正确的方式是将整个模板定义放在头文件中。 - Kerrek SB
你真正想做什么?typename不是模板参数的有效名称,在那段代码中,base继承自derived,这至少是一个违反直觉的命名选择。 - David Rodríguez - dribeas
抱歉...忽略类型名称...感谢大家提醒我...我刚刚将其更改为mytypename...除此之外...我只想知道我是否正确...我只希望我的模板定义和声明在不同的文件中。 - vadugs
@vadugs,阅读我的解答以获取解决方法(带有一些缺陷)。此外,Mark的答案提供了另一个解决方法,但需要额外的工作。 - Jimmy Lu
3个回答

3

类似的问题在SO上已经被问过很多次了。

但是无论如何...

首先,您犯了一些语法错误。

应该使用

#ifndef  ........
#define .....
 template <class typename>
 class abcBaseClass:public abcDerivedClass{
 public:
     typename getvalue(char*);
};
#endif

应该是这样的。

#ifndef  ........
#define .....
 template <typename T>
 class abcBaseClass:public abcDerivedClass{
 public:
     T getvalue(char*);
};
// Definition follow in this file!
// For reasons or work-arounds, read below.
#endif

同时,模板的声明和定义应该放在同一个文件中。唯一的例外是当您将模板实例化到某个类型时,模板定义在源文件中。

就像这样。

#include "this_template.h"

template <typename T>
// all sorts of definitions...

// Explicit instantiate this template!!!!
template class abcBaseClass<Your_Type_Goes_Here>;

请注意,这种方法的一个基本缺陷是,您只能在此源文件中显式实例化的类型中使用任何其他程序中。如果尝试使用其他类型来实例化此模板,则会导致链接器无法找到匹配的定义而发出投诉。
如果您坚持认为这个模板既要通用又要将模板类的定义放在其他地方。您可以将定义放入另一个头文件中,只需将其命名为像this_template_impl.h这样的内容,并在this_template_impl.h中包含this_template.h
然后,在您的源文件中,您可以写:#include "this_template_impl.h",而不是#include "this_template.h"

非常感谢您。我现在正在尝试将其放在一个文件中完成,并且我希望知道定义是如何完成的... 对于您所述的格式,这样做是否正确?abcDerivedClass::getvalue(char* name) - vadugs

1

你可以将定义放在.cpp文件中,但这样做会更麻烦,也不是模板通常的做法。

你需要在.cpp文件中添加一些额外的代码,以说服编译器生成带有必要模板参数的函数。其中一种方法是只需使用该函数:

mytypename abcDerivedClass<mytypename>::getvalue(char* name){

}

void dummy()
{
    abcDerivedClass<double> temp;
    temp->getvalue(NULL);
}

没有必要实际调用虚函数,只需要在模板定义后放置即可。

我确定还有另一种显式实例化模板的方法,但由于我不这样做,所以经常无法记住。


这只是一个 template typename abcDerivedClass<double>::getvalue(char*); - Seth Carnegie

0

不,这不是正确的方式:

应该这样做:

#ifndef  ........
#define .....
 template <class T>
 class abcBaseClass:public abcDerivedClass{
 public:
     T getvalue(char*)
};

#endif

在 .cpp 文件中:

template T abcBaseClass::getvalue(char * ch){ }

你的代码不正确的原因是因为 typename 是 C++ 的关键字,编译时必须会出现错误。

你也可以使用以下代码:

#ifndef  ........
#define .....
 template <typename T>
 class abcBaseClass:public abcDerivedClass{
 public:
     T getvalue(char*)
};
#endif

而在C++文件中:

template<class T>
T abcBaseClass<T>::getvalue(char * ch){
}

好的,你不能像在C++中处理其他事情那样将模板的定义放入.cpp文件中。虽然有一种解决方法,但它仍然与通常分离头文件/源文件的方式不同。 - Jimmy Lu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接