繁体   English   中英

在哪里定义C ++类成员模板函数和实例化它的仿函数?

[英]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。

我是不是该:

  • (A)将两个Functor类的定义和实现全部放在Foo.cpp中(实际上它们被其他Foo成员函数的实现用来调用Foo :: doSomething)。
  • (B)将两个Functor类的定义和实现放在Foo.h中。
  • (C)我应该将Foo.h和Foo.cpp中两个函数的定义和实现分开,就像普通类一样吗?

一般规则:

如果在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM