反向特征查找?

时间:2011-04-12 23:33:10

标签: c++

我一直在寻找解决以下问题的设计。 用几句话来形容。

我们有四种类型A1,A2,B和C.

我们想写一个函数fn,它将参数作为类型P。 使用特征,P在A1 / A2 / B / C内解析为PA1 / PA2 / PB / PC。

对于PA1和PA2,fn的实现是相同的,但确实如此 不同的PB和PC,它们之间以及它们之间的不同 PA1 / PA2。

#include <cassert>

struct PA1 {};
struct PA2 {};
struct PB  {};
struct PC  {};

struct A1 { typedef PA1 P; };
struct A2 { typedef PA2 P; };
struct B  { typedef PB  P; };
struct C  { typedef PC  P; };

template<typename T> char fn(typename T::P)
{
    return 'a';
}

char fn(B::P) {   return 'b';  }
char fn(C::P) {   return 'c';  }

int main()
{
    PA1 pa1;
    PA2 pa2;
    PB  pb;
    PC  pc;
    assert( fn<A1>(pa1) == 'a' );
    assert( fn<A2>(pa2) == 'a' );

    assert( fn(pb) == 'b' );
    assert( fn(pc) == 'c' );
}

上面代码的优点是fn的实现 PA1和PA2不重复。

但这是障碍。函数调用不是对称的。它是

fn<A1>(pa1)

fn<A2>(pa2)

表示A1 / A2 / PA1 / PA2,但只有fn(pb)和 B / C / PB / PC fn(pc)

这排除了在另一个(未示出)类中使用fn(..) 模板。

通常这不是问题。可以推导出模板参数 用于参数化功能。这在这里不起作用。我们要问 编译器在P解析的A1 / A2 / B / C中找到类型 到PA1 / PA2 / PB / PC之一。

你会做什么?

3 个答案:

答案 0 :(得分:1)

我认为你在这里混淆了两件事:

  

fnPA1

的实施PA2相同

不会阻止PA1PA2成为具有不同typedef的不同类型。

我们可以按原样使用:

template <typename PA>
char fn(PA pa) {
  typedef typename PA::type Type; // A1 or A2
  return 'a';
}

char fn(PB);
char fn(PC);

如果您无法实际修改P本身,则可以随时引入特征类。

template <typename T>
struct PTraits;

template <>
struct PTraits<PA1> { typedef A1 type; };

template <>
struct PTraits<PA2> { typedef A2 type; };

// ...

我会注意到Herb Sutter建议不要使用函数特化并且更喜欢重载,因为重载之间的交互(特别是涉及模板)是专门化非常棘手......并且很难理解哪个函数会被调用来自一组给定的参数。

答案 1 :(得分:0)

你真的不能让编译器逆转;如果两个结构Ptypedef int,会发生什么?

如果执行具有TT::P的一对一映射,那么您需要告诉编译器如何从T::P返回明确地T

答案 2 :(得分:0)

为了保持对称,您可以使用模板专业化:

template<> char fn<B>(B::P) {   return 'b';  }
template<> char fn<C>(C::P) {   return 'c';  }

然后你的电话看起来都像:

assert( fn<B>(pb) == 'b' );
assert( fn<C>(pc) == 'c' );

有趣的是,即使使用明确的模板实例化,例如:

template char fn<A1>(A1::P);
template char fn<A2>(A2::P);

我们没有得到推断类型。