[英]C++ instantiate function template as class member and using “this” pointer
[英]Where to define C++ class member template function and functors that instantiate it?
我有一个类Foo,用于一个小的独立项目。 它在Foo.h中有一个类定义,在实现文件Foo.cpp中实现了类的成员函数。
第一个问题 - 类Foo的成员函数之一是模板方法Foo :: doSomething(),这个方法的实现应该与Foo.h中的函数声明一起出现是否正确?
Foo :: doSomething()将被实例化的模板参数是两种Functor类型之一 - 类CalcA和CalcB。
我是不是该:
一般规则:
如果在foo.cpp之外使用foo :: doSomething()(即,如果它是公共的或通常是受保护的),它必须放在标题中。
如果没有,输入cpp文件是完全可以的,甚至是一个好主意(因为它使杂乱的文件远离头文件)。
因此,如果仿函数仅用于cpp文件,那么通常也会将模板函数放在那里。 如果这种情况发生变化,以后总能重构一下。
首先,您必须了解模板机制。 模板不会被编译,它们在使用时会被实例化,然后编译它们的实例化。 因此编译器需要使用模板函数在每个模块中拥有完整的模板定义,以便根据您传递的参数首先实例化它们。
要解决您的问题,有三种解决方案,但您会发现它们都会导致相同的结果。 您可以在类定义中的头文件中实现整个模板(我们使用.hxx而不是.h来后缀它们以确保它们包含模板定义):
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T& t) {
t.doSomething();
}
};
#endif
或者您可以从类中外部化定义,但仍然在头文件中:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
#endif
最后,您可以在外部文件中实现模板方法体(出于同样的原因,前缀为.cxx)。 它将包含方法的主体,但不包括“Foo.hxx”。 相反,它是“Foo.hxx”,它将在类定义后包含“Foo.cxx”。 这样,当编译器解析#include指令时,它会在同一模块中找到整个模板定义,允许它实例化它:
// Foo.hxx
#ifndef __FOO_HXX__
#define __FOO_HXX__
class Foo {
public:
template <class T>
void bar(const T&);
};
#include "Foo.cxx"
#endif
// Foo.cxx
template <class T>
void Foo::bar(const T& t) {
t.doSomething();
}
在这三种实现模板的方式之间进行选择取决于可读性(和品味)。
第二个和第三个在生成的代码方面是等价的,但我宁愿不使用cxx文件解决方案,因为当你忘记反转include时,它经常会导致愚蠢的错误。
此外,众所周知的C ++库(如STL或Boost)仅在头文件中提出它们的代码,这是良好设计的标志。 通过在标题内使用外部定义,您可以阐明类的定义。 您还可以阻止编译器自动内联方法,根据Herb Sutter http://www.gotw.ca/gotw/033.htm ,这有时会导致结果不佳
我的默认设置是将成员函数模板的定义放在.h文件中,如下所示:
class Foo
{
public:
template<typename T> void DoSomething(T t);
};
// ... later...
template<typename T>
void Foo::DoSomething(T t)
{
// ...
}
如果这对于特定情况来说不是最理想的话,那么我会采取更多英雄措施。 从#include
-ing .inc文件开始,带有.h文件末尾的定义,或者甚至可能在.cpp文件中进行显式实例化,我需要使用成员函数模板。
模板方法定义应该确实位于它所属的类的头文件中。
像这样:
class MyClass
{
template <typename T>
void foo(const T&)
{
// Definition
}
};
或者像这样(注意模板方法定义可以在类声明后从单独的文件中包含)
class MyClass
{
template <typename T> void foo(const T&);
};
template <typename T>
void MyClass::foo(const T&)
{
// Definition
}
其余的取决于您同意的风格和您的需求。
如果我不仅在Foo中使用它们或者如果Foo将它们作为类成员使用它,我会将functor声明(或者甚至定义,如果它们很简单)放入标题中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.