模板相互递归

时间:2017-10-13 16:18:25

标签: c++ templates recursion libraries

我希望在我的库中有一个模板函数func,以便用户可以使用自己的类型重载它。问题是我的类型系统的形式是

T := A<T>, B<T>, C

因此,如果template<class T> void func(A<T>);专门用于template<class T> void func(B<T>);,则T = B<C>需要func(B<T>)。相反,如果我们使用T = A<C>实例化B<T>,则A<T>专业化需要template<class T> class D<T>;专业化。

直到这里的问题才能解决,在一些公共标题中声明模板函数。

我不知道如何处理如何使这种类型的系统可扩展。我希望用户可以定义自己的类型template<class T> void func(D<T>);并实现自己的A<D<C>>。在这种情况下,我不知道用户如何转发声明她的类型,以便在专业化void func(A<T>);中,函数void func(D<T>);能够找到namespace ns { template<class T> struct A { T t; }; template<class T> void fun (A<T> a) { fun(a.t); } }

有没有标准的方法呢?

编辑问题的最小工作示例:

//在A.hpp

namespace ns {
template<class T> struct B { T t; };
template<class T>
void fun (B<T> b) { fun(b.t); }

// B.hpp

#include <iostream>
namespace other {
template<class T>
struct C {};
}

namespace ns {
template<class T>
void fun(other::C<T> c) { std::cout << "C" << std::endl; }
}

// C.hpp

#include "A.hpp"
#include "B.hpp"
#include "C.hpp"

namespace ns {
void f () {
    fun(A<B<other::C<int>>>());
}
}


int main () {
    ns::f();
}

// main.cpp

main.cpp

这个例子没有编译。如果我们将#include "C.hpp" #include "B.hpp" #include "A.hpp" 中的包含重新排序为

,它就会编译
A<B<C<int>>>

现在,这显然是一个黑客攻击。使用此设计,用户将无法同时实例化B<A<C<int>>>A。对此的解决方案是在其他模板中转发声明BA.hpp,并将其包含在B.hpptemplate<class T> class D;中。当您尝试让库的用户定义自己的类型时,问题就出现了。如果库的用户定义了自己的类型A<D<C<int>>>,则她无法转发声明,然后,如果她尝试实例化other,则编译将失败。

在此示例中,名称空间C表示我无法控制的名称空间,而boost表示某个其他库中的预先存在的类。这可以被认为是一些ns类或类似的。 fish_title命名空间是我的库定义的命名空间。

1 个答案:

答案 0 :(得分:1)

如果fun()是模板类中的静态方法呢?

所以你可以部分专门化这门课程吗?

我的意思是

// 000.h

#ifndef h_000__h
#define h_000__h

namespace ns
 {
   template <typename T>
   struct foo;
 }

#endif

// 001.h

#ifndef h_001__h
#define h_001__h

#include <iostream>

#include "000.h"

namespace ns
 {
   template<class T>
   struct A
    { T t; };

   template <typename T>
   struct foo<A<T>>
    {
      static void fun (A<T> a)
       { std::cout << "A<T> fun" << std::endl; foo<T>::fun(a.t); }
    };
 }

#endif

// 002.h

#ifndef h_002__h
#define h_002__h

#include <iostream>

#include "000.h"

namespace ns
 {
   template <typename T>
   struct B
    { T t; };

   template <typename T>
   struct foo<B<T>>
    {
      static void fun (B<T> a)
       { std::cout << "B<T> fun" << std::endl; foo<T>::fun(a.t); }
    };
 }

#endif

// 003.h

#ifndef h_003__h
#define h_003__h

#include <iostream>

#include "000.h"

namespace other
 {
   template <typename T>
   struct C
    { };
 }

namespace ns
 {
   template <typename T>
   struct foo<other::C<T>>
    {
      static void fun (other::C<T> a)
       { std::cout << "C<T> fun" << std::endl; }
    };
 }

#endif

// main.cpp

#include "001.h"
#include "002.h"
#include "003.h"

namespace ns
 {
   void f ()
    {
      using type = A<B<other::C<int>>>;

      foo<type>::fun(type{});
    }
 }

int main ()
 {
   ns::f(); // print A<T> fun \n B<T> fun \n C<T> fun \n
 }