我希望在我的库中有一个模板函数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
。对此的解决方案是在其他模板中转发声明B
和A.hpp
,并将其包含在B.hpp
和template<class T> class D;
中。当您尝试让库的用户定义自己的类型时,问题就出现了。如果库的用户定义了自己的类型A<D<C<int>>>
,则她无法转发声明,然后,如果她尝试实例化other
,则编译将失败。
在此示例中,名称空间C
表示我无法控制的名称空间,而boost
表示某个其他库中的预先存在的类。这可以被认为是一些ns
类或类似的。 fish_title
命名空间是我的库定义的命名空间。
答案 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
}