我可以使用元编程将类型列表转换为对列表中的每种类型具有特定隐式转换行为的新类型吗?

Can I use metaprogramming to transform a list of types into a new type that has specific implicit-conversion behavior to each type in the list?

我有一个 boost::mpl::vector 包含几种类型,例如

typedef boost::mpl::vector<T1, T2, T3, T4> list_type;

对于某些已知类型 T1, T2, T3, T4。有没有办法使用元编程将这个列表转换为表示直接线性继承的类型,按照向量中类型的顺序?我想合成一个具有与此一致的行为的类型:

struct T1 { };
struct T2 : T1 { };
struct T3 : T2 { };
struct T4 : T3 { };
struct synthesized_type : T4 { };

boost::mpl::inherit_linearly 给了我类似的行为,但不完全是我想要的。使用它产生的类型更像:

struct synthesized_type : T1, T2, T3, T4 { };

在某些情况下表现不同。例如,假设您有一个函数在 T1, T2, T3, T4:

类型的某些子集上重载
void foo(T1) { }
void foo(T3) { }

foo(synthesized_type()); // I would like to be able to do this

对于我上面给出的第一个(期望的)层次结构,重载解析没有歧义;我可以将 synthesized_type 传递给 foo(),它会调用 foo(T3),因为 T3synthesized_type.

祖先中最派生的类型

然而,在我使用 boost::mpl::inherit_linearly 的情况下,由于在父类型之间没有指定优先级,因此由于重载决策的歧义导致编译器错误;编译器无法在 foo(T1)foo(T3).

之间进行选择

有什么方法可以达到我想要的效果吗?更正式地说:

Given a list of types, I would like to use metaprogramming to synthesize some type that has the properties of the first hierarchy I described above (namely, that the synthesized type is implicitly convertible to each type T1, T2, T3, T4, with priority in that order, so T4 is preferred to T3, which is preferred to T2, and so on). Is this possible?

如果你的类型都是 CRTP 类型你可以做这个魔法:

#include <iostream>

template< template<class> class... Ts >
struct TVec { };

struct EmptyClass { };

template< class T >
struct Inheritor;

template< template<template<class> class> class U, template<class> class T>
struct Inheritor< U<T> >
  : public T<EmptyClass> { };

template< template<template<class> class...> class U, template<class> class T, template<class> class... Ts>
struct Inheritor< U<T, Ts... > >
  : public T<Inheritor< U<Ts...> > > { } ;

template< typename Base >
struct T1
  : public Base { };

template< typename Base >
struct T2
  : public Base { };

template< typename Base >
struct T3 
  : public Base { };

template<typename X>
void foo(T1<X> t) {
  std::cout << "T1" << std::endl;
}

template<typename X>
void foo(T2<X> t) {
  std::cout << "T2" << std::endl;
}

template<typename X>
void foo(T3<X> t) {
  std::cout << "T3" << std::endl;
}

int main() {
  using Types = TVec< T1, T2, T3 >;
  using Types2 = TVec< T3, T2, T1 >;

  using Derived = Inheritor<Types>;
  using Derived2 = Inheritor<Types2>;

  //Inheritor<TVec< T1, T2, T3>> x;
  Derived x;
  Derived2 x2;

  foo(x); // T1 overload
  foo(x2); // T3 overload
}

您无法得到那个确切的行为,因为它会涉及重新定义 T1、T2...这足够接近了吗?

template< class T >
struct Inheritor { };

template< class T, template<class> class U >
struct Inheritor< U<T> >
  : public T { };

template< template<class...> class U, class T, class... Ts >
struct Inheritor< U<T, Ts...> >
  : public T
  , public Inheritor< U< Ts... > > { };