2017-10-16 98 views
-2

我有以下声明一个类A(阿文件):与模板函数循环依赖

#ifndef __A_DEFINED__ 
#define __A_DEFINED__ 

class A 
{ 
public: 
    template<typename T> inline void doThat() const; 
}; 

#endif 

和B类从该类(BH文件)推导出:

#ifndef __B_DEFINED__ 
#define __B_DEFINED__ 

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

class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

#endif 

所以远,那么好。我的问题是,函数A ::找时间做()使用B :: doThis():在

template<typename T> inline void A::doThat() const { B b; b.doThis(); } 

一般情况下,循环依赖不会是一个问题,因为我也只是定义了A ::找时间做() .cpp文件。但在我的情况下,doThat是一个模板函数,所以我不能这样做。

这里是我到目前为止所设想的解决方案:

  1. 定义模板功能A::doThat()在.cpp文件。与此相关的问题是,我需要显式实例化具有各种模板参数的所有调用(实际情况中可能有很多)。

  2. 在A.h中声明A类后,添加#include "B.h",然后定义A::doThat()函数。这在Visual Studio中运行良好,但是g ++不喜欢它。

有没有一种简洁的方法来解决这个问题?在真实情况下,不仅有一个孩子类B,而且有几个(B,C,D等)。函数A :: doThat()取决于它们中的所有孩子。函数B :: doThis()也是模板化的。

+2

无关:任何在一行中有两个下划线的标识符都被保留供实现使用。使用它们需要您自担风险。更多信息在这里:[有关在C++标识符中使用下划线的规则是什么?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in- ac-identifier) – user4581301

回答

1

B类的缺省模板参数可以工作:

#include <iostream> 

// include A.h 
class B; 

class A 
{ 
public: 
    template<typename T, typename U = B> inline void doThat() const 
    { 
     U b; b.doThis(); 
    } 
}; 

// include B.h 
class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

// main 
int main() 
{ 
    A a; 
    a.doThat<int>(); 
} 
+0

这只适用于默认的模板参数,或者即使在此定义函数?我是这样说的,因为在真实情况下,doThat()取决于B,但也取决于孩子C,D和E. – Touloudou

+0

@Touloudou这听起来像是一个相关的,但不同的问题与不同的答案。 – wally

1

通常是最好的方式,让家长调用子函数声明函数作为家长和覆盖纯虚函数它在孩子们。

#include <iostream> 

class A 
{ 
public: 
    virtual ~A() = default; 
    template<typename T> inline void doThat() const 
    { 
     // do some other stuff 
     doThis(); 
    } 
    virtual void doThis() const = 0; // pure virtual function 
}; 

class B: public A 
{ 
public: 
    void doThis() const override 
    { 
     std::cout << "do this!" << std::endl; 
    } 
}; 

int main() 
{ 
    B b; 
    A* ap = &b; 
    ap->doThat<int>(); 
} 
+0

这里的问题是doThis()函数也应该在实际情况下进行模板化。这意味着这将是一个虚拟模板函数,在当前C++中是不行的。 – Touloudou

+0

@Touloudou这是真正重要的信息在问题中。您应该编辑问题并添加它。如果模板没有(或简单)参数,则可以将模板化函数抽象为常规模板。 – user4581301

0

下确实与g++工作:

文件A.h

#ifndef __A_DEFINED__ 
#define __A_DEFINED__ 

class A 
{ 
public: 
    template<typename T> inline void doThat() const; 
}; 

#include "B.h" 

template<typename T> inline void A::doThat() const { B b; b.doThis(); } 

#endif 

文件B.h

#include <iostream> 

#include "A.h" 

// We check for the include guard and set it AFTER the inclusion of A.h 
// to make sure that B.h is completely included from A.h again. 
// Otherwise the definition of A::doThat() would cause a compiler error 
// when a program includes B.h without having included A.h before. 
#ifndef __B_DEFINED__ 
#define __B_DEFINED__ 

class B : public A 
{ 
public: 
    void doThis() const { std::cout << "do this!" << std::endl; } 
}; 

#endif 

文件test_A.cpp

// In this test case we directly include and use only A. 
#include "A.h" 
#include "A.h" // We test whether multiple inclusion causes trouble. 

int main() { 
    A a; 
    a.doThat<int>(); 
} 

文件test_B.cpp

// In this test case we directly include and use only B. 
#include "B.h" 
#include "B.h" // We test whether multiple inclusion causes trouble. 

int main() { 
    B b; 
    b.doThat<int>(); 
    b.doThis(); 
} 

另外一个设想:

我不知道你(或某些编码约定)是否坚持为每个类单独的头文件,但如果没有以下应工作:

你可以把class Aclass B的定义和成员函数模板的(以此顺序)在一个头文件AandB.h(或任何你喜欢的名字)中。

+0

@Touloudou根据你的想法,我得到了你用'g ++'工作的问题2.我不得不移动包含守卫(参见B.h中的评论)。 – Fabian