2017-10-13 130 views
0

我想在我的库中有一个模板函数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>);

有没有这样做的标准方式?

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

//在A.hpp

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

// B.hpp

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

// C.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; } 
} 

// main.cpp

#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作为

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

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

在这个例子中,命名空间other代表一个名字空间,我没有控制权,并且C表示在其他一些库中的预先存在的类。这可以被认为是一些boost类或类似的。命名空间ns是我的库定义的名称空间。

+3

请出示一些实际的代码。 –

+0

我可以猜出你的意思是“表格”,但我很容易出错。草拟该想法的实际代码摆脱了许多不明确之处。 'T:= A '至少在同一陈述中滥用了一个重复使用的'T'来表示两个不同的事物,而且我不确定这个逗号是否表明了一些奇怪的回忆,或者它只是一个'T '可以。通过编辑显示你的计划的问题的实际代码(这个代码应该编译) – Yakk

+0

通过':='我打算为术语'T'定义一个语法。 我想在一个简短的例子中复制这种行为,代码编译依赖于包含的顺序。 – Lezkus

回答

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 
} 
+0

这正是我所寻找的解决方案。谢谢! – Lezkus