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

2023-12-12

Question

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

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

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

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


Test 1(公共继承)

  • 我不想继承公共方法。

Test 2(定义 1 + 2 + ... n 个转换运算符):

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

Test 3(每个类 1 个转换运算符):

  • 只允许从下一个级别的类型到本级别的类型的转换。

例如,这可以实现从 D 到 C 的转换,但不能从 D 到 B 的转换。

测试(也在上帝螺栓.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 层定义图节点的内存组织 (指针/数组)。

  • Type 2 层将一个层转换为另一个容器。 (例如,具有哈希值的层,用于通过键对节点进行索引并跟踪节点的交换。)

用户可以通过多种方式堆叠层来创建对象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, i.e. may_convert<...>::value is true),或者直到模板用完(在这种情况下may_convert<...>::value is false).

现在,剩下的就是适当地限制你的构造函数:

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 is true。否则,转换将会失败。


Examples

以下是如何操作的示例may_convert在您的示例中有效(从D = A<A<A<int>>> to B = A<int>):

  • 构造函数仅存在于may_convert<A, D, B>::value is true

  • may_convert<A, D, B>匹配最后一个专业化(因为D = A<C> and B = A<int>,参数推导为T = C and U = int)并继承自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>不应该转换为B:

  • 仅在以下情况下才会启用构造函数may_convert<A, E, B>::value is true

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

  • Because double不是一个A<...>,没有一个专业化匹配,所以我们回退到默认情况,它继承自std::false_type.

  • 所以,may_convert<A, E, B>::value is false,并且转换失败。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

没有公共继承的类之间的链式转换 的相关文章

  • 如何在 Unity 中从 RenderTexture 访问原始数据

    问题的简短版本 我正在尝试访问 Unity 中 RenderTexture 的内容 我一直在使用 Graphics Blit 使用自己的材质进行绘制 Graphics Blit null renderTexture material 我的材
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 跨多个控件共享事件处理程序

    在我用 C 编写的 Windows 窗体应用程序中 我有一堆按钮 当用户的鼠标悬停在按钮上时 我希望按钮的边框发生变化 目前我有以下多个实例 每个按钮一个副本 private void btnStopServer MouseEnter ob
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • 用 C 实现 Unix shell:检查文件是否可执行

    我正在努力用 C 语言实现 Unix shell 目前正在处理相对路径的问题 特别是在输入命令时 现在 我每次都必须输入可执行文件的完整路径 而我宁愿简单地输入 ls 或 cat 我已经设法获取 PATH 环境变量 我的想法是在 字符处拆分
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr

随机推荐