没有公共继承的类之间的链式转换

时间:2018-05-12 14:29:25

标签: c++ oop type-conversion

问题

我有一系列~10个模板类A,B,C,D,......

我想启用从类到系列中以前的类的转换:

  • D - > C,B或A
  • C - > B,或A
  • B - > A

如何在不使用公共继承的情况下实现这一目标?

测试1 (公共继承)

  • 我不想继承公共方法。

测试2 (定义1 + 2 + ... n转换运算符):

  • 为第n个模板类定义n个转换运算符 模板类。
  • 非常乏味

测试3 (每班1个转换运算符):

  • 仅允许从下一级别的类型转换为此级别的类型。

例如,它允许从D转换为C,但不能从D转换为B.

测试(也在godbolt.org):

template <typename Convertible>
class A {
public:
    operator Convertible() { return Convertible(); }
};

using B = A<int>;
using C = A<B>;
using D = A<C>;

int main() {
    D d;
    auto b = B(d);
    return 0;
}

编译错误:

error: no matching function for call to ‘A<int>::A(D&)’
     auto b = B(d);
                 ^

实际使用案例

A,B,C,D ......是由对象S层创建的每个节点(代理)。

  • 类型1层定义图形节点的内存组织 (指针/阵列)。

  • 第2层将图层转换为另一个容器。 (例如,带有散列的层,用于按键索引节点和跟踪节点的交换。)

用户可以通过多种方式堆叠图层来创建对象S.

我希望一层的节点转换为先前层的节点。

这是可能的,因为指向节点内容的/ index的指针是相同的。

1 个答案:

答案 0 :(得分:2)

您可以通过使用std::enable_if和一些模板元编程约束模板化构造函数(将在转换中使用)来实现此目的:

template <template <class> typename BaseTemplate,
          typename From,
          typename To,
          typename Enable = void>
struct may_convert
    : public std::false_type {};

template <template <class> typename BaseTemplate,
          typename T>
struct may_convert<BaseTemplate, BaseTemplate<T>, BaseTemplate<T>, void>
    : public std::true_type {};

template <template <class> typename BaseTemplate,
          typename T,
          typename U>
struct may_convert<BaseTemplate, BaseTemplate<T>, BaseTemplate<U>, 
                   typename std::enable_if<!std::is_same<T, U>::value>::type>
    : public may_convert<BaseTemplate, T, BaseTemplate<U>> {};

may_convert会走向From模板参数的模板,直到它等于To(在这种情况下,它继承自std::true_type,即may_convert<...>::value } {是true),或者在模板用完之前(在这种情况下may_convert<...>::valuefalse)。

现在,剩下的就是适当地约束你的构造函数了:

template <typename Convertible>
class A {
public:
    A() {}

    template <typename T,
              typename = typename std::enable_if<
                  may_convert<A, T, A<Convertible>>::value>::type>
    A(const T&) {}
};

这样,仅当may_convert<...>::valuetrue时,构造函数才存在。否则,转换将失败。

实施例

以下是may_convert在您的示例中的工作原理示例(从D = A<A<A<int>>>转换为B = A<int>):

  • 只有当may_convert<A, D, B>::valuetrue

  • 时,构造函数才存在
  • may_convert<A, D, B>匹配上一个专门化(因为D = A<C>B = A<int>,参数推断为T = CU = int)并且继承自{ {1}}

  • may_convert<A, C, B>再次匹配上一个专门化(may_convert<A, C, B>T = B)并继承自U = int

  • 这次,两种类型相同,所以第一次特化匹配,整个事物继承自may_convert<A, B, B>,启用构造函数。

另一方面,假设std::true_type不应转换为using E = A<double>

  • 只有Bmay_convert<A, E, B>::value

  • 时才会启用构造函数
  • true与上一次专精化相匹配,并继承自may_convert<A, E, B>

  • 由于may_convert<A, double, B>不是double,因此没有一个专业化匹配,因此我们回到默认情况,它继承自A<...>

    < / LI>
  • 因此,std::false_typemay_convert<A, E, B>::value,转换失败。