C++ 元编程中的 typedef 与公共继承

2024-04-03

免责声明:这个问题与继承而不是 typedef https://stackoverflow.com/questions/441744/inheritance-instead-of-typedef到目前为止我找不到任何类似的问题

我喜欢玩 C++ 模板元编程(主要是在家里,有时我在工作中轻轻介绍它,但我不希望该程序变得只有那些不费心去学习它的人才能阅读),但是我一直在每当出现问题时,编译器错误都会让你很恼火。

问题在于,c++ 模板元编程当然是基于模板的,因此每当您在深度嵌套的模板结构中遇到编译器错误时,您都必须在 10 行错误消息中挖掘出自己的方法。我什至养成了在文本编辑器中复制/粘贴消息的习惯,然后缩进消息以获得某种结构,直到我了解实际发生的情况,这增加了跟踪错误本身的一些工作。

据我所知,问题主要是由于编译器及其输出 typedef 的方式造成的(还有其他问题,例如嵌套深度,但实际上并不是编译器的错误)。即将推出的 C++0x 宣布了一些很酷的功能,例如可变参数模板或类型推导(自动),但我真的希望有更好的错误消息来启动。使用模板元编程可能会很痛苦,我确实想知道当更多的人真正使用它们时,这会变成什么样子。

我已经替换了代码中的一些 typedef,并改用继承。

typedef partition<AnyType> MyArg;

struct MyArg2: partition<AnyType> {};

这并不需要输入更多的字符,而且在我看来,这并不影响可读性。事实上,它甚至可能更具可读性,因为它保证声明的新类型出现在靠近左边距的位置,而不是位于右侧未确定的偏移处。

然而这又涉及到另一个问题。为了确保我没有做任何愚蠢的事情,我经常像这样编写模板函数/类:

template <class T> T& get(partition<T>&);

这样我就确信只能为合适的对象调用它。

特别是当重载运算符(例如运算符+)时,您需要某种方法来缩小运算符的范围,或者冒着被调用 int 等操作的风险。

但是,如果这适用于 typedef'ed 类型,因为它只是一个别名。它肯定不适用于继承......

对于函数,可以简单地使用CRTP http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

template <class Derived, class T> partition;

template <class Derived, class T> T& get(partition<Derived,T>&);

这允许在编译器使用公共继承之前知道用于调用该方法的“真实”类型。应该注意的是,这减少了必须调用该特定函数的机会,因为编译器必须执行转换,但到目前为止我从未注意到任何问题。

此问题的另一种解决方案是向我的类型添加“标签”属性,以区分它们,然后依靠SFINAE http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error.

struct partition_tag {};

template <class T> struct partition { typedef partition_tag tag; ... };

template <class T>
typename boost::enable_if<
  boost::same_type<
    typename T::tag,
    partition_tag
  >,
  T&
>::type
get(T&)
{
  ...
}

不过,它需要更多的输入,特别是如果在不同的地方声明和定义函数/方法(如果我不打扰的话,我的界面很快就会变得混乱)。然而,当涉及到类时,由于没有执行类型转换,所以它确实变得更加复杂:

template <class T>
class MyClass { /* stuff */ };

// Use of boost::enable_if

template <class T, class Enable = void>
class MyClass { /* empty */ };

template <class T>
class MyClass <
  T,
  boost::enable_if<
    boost::same_type<
      typename T::tag,
      partition_tag
    >
  >
>
{
  /* useful stuff here */
};

// OR use of the static assert

template <class T>
class MyClass
{
  BOOST_STATIC_ASSERT((/*this comparison of tags...*/));
};

我倾向于使用更多的“静态断言”而不是“enable_if”,我认为当我在一段时间后回来时它更具可读性。

好吧,基本上我还没有下定决心,我仍在尝试这里公开的不同技术。

你使用 typedef 还是继承? 如何限制方法/函数的范围或以其他方式控制提供给它们(以及类)的参数类型?

当然,如果可能的话,我想要更多个人喜好。如果有充分的理由使用某种特定技术,我宁愿知道它!

EDIT:

我正在浏览 stackoverflow,刚刚从 Boost.MPL 中找到了这个 perl,我完全忘记了:

BOOST_MPL_ASSERT_MSG http://www.boost.org/doc/libs/1_39_0/libs/mpl/doc/refmanual/assert-msg.html

这个想法是你给宏 3 个参数:

  • 要检查的条件
  • 应用于在错误消息中显示的消息(C++ 标识符)
  • 涉及的类型列表(作为元组)

它可能对代码自我文档和更好的错误输出有很大帮助。


您想要做的是显式检查作为模板参数传递的类型是否提供必要的概念。由于缺少被 C++0X 抛弃的概念功能(因此成为 C++1X 的罪魁祸首之一),因此很难进行适当的概念检查。自 20 世纪 90 年代以来,人们曾多次尝试在没有语言支持的情况下创建概念检查库,但基本上,所有这些所取得的成就都是为了表明,为了做得正确,概念需要成为核心语言的一个功能,而不是成为核心语言的一个功能。而不是仅包含库的功能。

我没有找到你的推导而不是想法typedef并使用enable_if非常吸引人。正如您自己所说,它通常只是为了更好的编译器错误消息而掩盖实际代码。

我发现静态断言要好得多。它不需要改变实际的代码,我们都习惯在算法中进行断言检查,并且如果我们想理解实际的算法,就学会在心里跳过它们,它可能会产生更好的错误消息,并且它将延续到 C ++1X 更好,这将有一个static_assert(完全包含类设计者提供的错误消息)内置于语言中。 (我猜测BOOST_STATIC_ASSERT只需使用内置的static_assert如果可以的话。)

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

C++ 元编程中的 typedef 与公共继承 的相关文章

  • 向进度条添加百分比文本 C#

    我有一个方法可以显示进程栏何时正在执行以及何时成功完成 我工作得很好 但我想添加一个百分比 如果完成 则显示 100 如果卡在某个地方 则显示更少 我在网上做了一些研究 但我无法适应我正在寻找的解决方案 这是我的代码 private voi
  • 注销租约抛出 InvalidOperationException

    我有一个使用插件的应用程序 我在另一个应用程序域中加载插件 我使用 RemoteHandle 类http www pocketsilicon com post Things That Make My Life Hell Part 1 App
  • 确保 StreamReader 不会挂起等待数据

    下面的代码读取从 tcp 客户端流读取的所有内容 并且在下一次迭代中它将仅位于 Read 上 我假设正在等待数据 我如何确保它不会在没有任何内容可供读取时返回 我是否必须设置低超时 并在失败时响应异常 或者有更好的办法吗 TcpClient
  • 在 C 中匹配二进制模式

    我目前正在开发一个 C 程序 需要解析一些定制的数据结构 幸运的是我知道它们是如何构造的 但是我不确定如何在 C 中实现我的解析器 每个结构的长度都是 32 位 并且每个结构都可以通过其二进制签名来识别 举个例子 有两个我感兴趣的特定结构
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 回发后刷新时提示确认表单重新提交。我做错了什么?

    我有一个以空白 默认状态启动的仪表板 我让用户能够将保存的状态加载到仪表板中 当他们单击 应用 按钮时 我运行以下代码 function CloseAndSave var radUpload find radUpload1ID var in
  • 如何使用 LINQ2SQL 连接两个不同上下文的表?

    我的应用程序中有 2 个数据上下文 不同的数据库 并且需要能够通过上下文 B 中的表的右连接来查询上下文 A 中的表 我该如何在 LINQ2SQL 中执行此操作 Why 我们正在使用 SaaS 产品来跟踪我们的时间 项目等 并希望向该产品发
  • 是否有实用的理由使用“if (0 == p)”而不是“if (!p)”?

    我倾向于使用逻辑非运算符来编写 if 语句 if p some code 我周围的一些人倾向于使用显式比较 因此代码如下所示 if FOO p some code 其中 FOO 是其中之一false FALSE 0 0 0 NULL etc
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • Qt - ubuntu中的串口名称

    我在 Ubuntu 上查找串行端口名称时遇到问题 如您所知 为了在 Windows 上读取串口 我们可以使用以下代码 serial gt setPortName com3 但是当我在 Ubuntu 上编译这段代码时 我无法使用这段代码 se
  • 如何在 Xaml 文本中添加电子邮件链接?

    我在 Windows Phone 8 应用程序中有一些大文本 我希望其中有电子邮件链接 例如 mailto 功能 这是代码的一部分
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 使用 C# 读取 Soap 消息

  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • 无法接收 UDP Windows RT

    我正在为 Windows 8 RT 编写一个 Windows Store Metro Modern RT 应用程序 需要在端口 49030 上接收 UDP 数据包 但我似乎无法接收任何数据包 我已按照使用教程进行操作DatagramSock
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 当从finally中抛出异常时,Catch块不会被评估

    出现这个问题的原因是之前在 NET 4 0 中运行的代码在 NET 4 5 中因未处理的异常而失败 部分原因是 try finallys 如果您想了解详细信息 请阅读更多内容微软连接 https connect microsoft com

随机推荐

  • Powershell 将行转置为列

    有人可以帮我将行转置为列吗 需要将机器名称转置到列中 结束时间必须排序 lt MachineName TotalDataSizeBytes ActualStartTime EndTime FinalJobStatus SERVER1 322
  • 如何从 uitableviewcell 显示 uidatepicker [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 询问代码的问题必须对所解决的问题表现出最低限度的了解 包括尝试的解决方案 为什么不起作用以及预期结果 也可以看看 Stack Overfl
  • 如何在 Spring 中查看 SOAP 请求的 XML 输出?

    我是 Spring SOAP 请求的新手 我想查看 SOAP 请求的最终 XML 输出 其中包括 SOAP 标头和 SOAP 信封 在调试时我到达了这段代码 sendSourceAndReceiveToResult partnerURI s
  • Xamarin Forms Flex 布局大小调整问题

    在我的 Xamarin Forms 应用程序中 我需要在另一个 Flex 布局内有一个 Flex 布局 这是因为 我的应用程序中需要有两列 一列占据屏幕的 80 另一列占据屏幕的 20 我使用具有两个子级的 FlexLayout 为此设置了
  • Xcode 12.4 中未找到框架 FIRAnalyticsConnector

    在 Xcode 12 4 中更新 pod 后出现 找不到框架 FIRAnalyticsConnector 错误 我已经清理并重建了该项目 但它仍保留在那里 我应该怎么办 转到您的项目目标Build Settings gt 搜索FIRAnal
  • 每次迁移后都需要重新启动 Heroku 吗?

    最近我遇到了一个问题 我的数据库方案更改没有反映在 Heroku PG 上 我仔细检查了一下 发现迁移和种子都成功了 更奇怪的是 数据库方案更改在暂存的 Heroku 部署上运行良好 在完全相同的迁移 种子之后 经过一番搜索后 我了解到您应
  • PHP 中每个文件只有一个或多个函数?

    每当我用 php 设计我的应用程序时 我都会遇到这个问题 这确实让我头疼 我不知道是否应该为每个函数创建单独的文件 例如 用于验证特定表单的函数 好吧 有人可能会认为这没有意义 因为我必须单独包含每个文件 这可能会导致应用程序更慢 但我仍然
  • C++ - 检测超出范围的访问

    我想分析我的 C 代码以查找向量和数组中的错误访问 超出范围访问 是否有工具可以实现这一点 提前致谢 如果您使用的是 gcc 则可以使用定义的 GLIBCXX DEBUG 和 GLIBXX DEBUG PEDATIC 进行编译 如果请求越界
  • 如何修改此 sed awk 命令以便输出到所选文件?

    我正在使用这个答案中的最后一个命令https stackoverflow com a 54818581 80353 https stackoverflow com a 54818581 80353 cap cd tmp rm f vtt y
  • 对 AngularJS 依赖注入不一致感到困惑

    我是新来的angular js 并浏览了几个教程 包括此处的所有教程代码学校 http campus codeschool com courses shaping up with angular js intro 我发现它们非常有用 并且学
  • Google Play 开发者控制台:支持的 Android 设备:0

    我尝试过多次上传 我还查看了有关同一问题的许多其他问题 在我的物理设备上运行良好 但上传到 google play 时显示它支持 0 个设备
  • 为什么我会在 .NET 的 StartsWith 中看到这种意外行为?

    这一定是一个 NET 错误 对吧 KonNy StartsWith Kon 返回 false 同时 KonNy StartsWith Ko and KonN StartsWith Kon 返回真 我在这里缺少什么吗 重复评论 我不太了解 N
  • 使用 fql 检查 Facebook 用户是否喜欢某个页面

    我想检查登录用户是否喜欢指定的页面 下面是我的代码 fql pageid SELECT url site id FROM object url WHERE url IN http developers facebook com api pa
  • 将本地分支合并到远程分支而不是master?

    我有一个本地分支 A 但远程存储库中尚不存在 我在远程仓库中还有一个远程分支 B 如何将本地更改合并到远程分支 如果分支 B 在本地 您可以在本地合并 A 到 B 然后将 B 推送到远程 git checkout B git merge A
  • ASP.NET 中的简单 Web 部件显示为空白页

    我正在尝试开发 Web 部件VS 2008 WinXP 我创建了一个网站项目 并在默认表单中添加了几个 Web 部件default aspx
  • 无法通过curl访问github

    尝试使用以下命令访问 github 失败 并出现验证失败错误 我应该怎么做才能解决这个问题 C software curl 7 23 1 win64 ssl sspi gt curl i https api github com curl
  • 在 Bash 中分割逗号分隔的字符串

    我有这个文件 里面有 20k IP 104 20 15 220 104 20 61 219 104 20 62 219 104 20 73 221 104 20 74 221 104 20 14 220 104 20 15 220 104
  • C# 奇怪的 WPF 组合框行为

    I have simple window This is what happens when I click ComboBox List appears in upper left corner of screen instead of u
  • 构建 Erlang 服务器场(用于业余爱好项目)最便宜的方法是什么? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 假设我们有一个 本质上并行 的问题需要用 Erlang 软件来解决 我们有很多并行进程 每个进程都执行顺序代码 不是数字运算 并且我们向它们投入的 C
  • C++ 元编程中的 typedef 与公共继承

    免责声明 这个问题与继承而不是 typedef https stackoverflow com questions 441744 inheritance instead of typedef到目前为止我找不到任何类似的问题 我喜欢玩 C 模