c++ - 没有公共(public)继承的类之间的链式转换

标签 c++ oop type-conversion

问题

我有一系列约 10 个模板类 A、B、C、D...

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

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

如何在不使用公共(public)继承的情况下做到这一点?


测试 1(公共(public)继承)

  • 我不想继承公共(public)方法。

测试 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 层将一个层转换为另一个容器。 (例如,带有用于通过键 inode 和跟踪节点交换的散列层。)

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

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

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

最佳答案

您可以通过使用 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<...>::valuetrue ),或者直到模板用完(在这种情况下 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<...>::value 时构造函数才存在是true .否则,转换将失败。


例子

这里是一个如何may_convert的例子在您的示例中有效(从 D = A<A<A<int>>> 转换为 B = A<int> ):

  • 只有在 may_convert<A, D, B>::value 时构造函数才存在是true

  • may_convert<A, D, B>匹配最后一个特化(因为 D = A<C>B = A<int> ,参数推导为 T = CU = int )并继承自 may_convert<A, C, B>

  • may_convert<A, C, B>再次匹配最后一个特化( T = BU = int )并继承自 may_convert<A, B, B>

  • 这一次,这两种类型是相等的,所以第一个特化匹配,整个东西继承自 std::true_type , 启用构造函数。

另一方面,想象一个 using E = A<double>不应转换为 B :

  • 只有在 may_convert<A, E, B>::value 时才会启用构造函数是true

  • may_convert<A, E, B>匹配最后一个特化,并继承自 may_convert<A, double, B>

  • 因为 double不是 A<...> , 没有任何专业匹配,所以我们回到默认情况,它继承自 std::false_type .

  • 因此,may_convert<A, E, B>::valuefalse , 转换失败。

关于c++ - 没有公共(public)继承的类之间的链式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50307311/

相关文章:

c++ - QPieSlice的Qt坐标

c++ - 指针和非指针类型的重载 -> 运算符

c++ - g++ makefile,多个cpp,每个都有自己的main()

iphone - 在类之间传递数据/异步请求/iOS

c++ - 向上转换为基类时如何使用继承的类成员的值

c++ - 为什么 `*this` 解析为子类?

c# - 在 C# 中,如何在给定类型名称的情况下创建对象?

c++ - 通过指向基类函数的指针调用派生类函数

c - C中可以存储非常大的值的数据类型

python - 将列表项转换为定义的数据类型