跨文件的代码组织必须处理模板函数和内联

2024-01-01

我正在维护一个大型模板类库,它们基于以下任意一个执行代数计算float or double类型。许多类都有访问器方法(getter 和 setter)和其他运行少量代码的函数,因此当编译器找到它们的定义时,需要将这些函数限定为内联。相比之下,其他成员函数包含复杂的代码,因此最好调用而不是内联。

函数定义的很大一部分位于标头中,实际上位于标头包含的 .inl 文件中。但也有许多类的函数定义通过显式实例化而愉快地存在于 .cpp 文件中float and double,这对于图书馆来说是一件好事(here https://stackoverflow.com/questions/2351148/explicit-instantiation解释了原因)。最后,有相当多的类的函数定义分散在 .inl 文件(访问器方法)和 .cpp 文件(构造函数、析构函数和繁重计算)中,这使得它们都非常难以维护。

仅当我知道一种可靠的方法来防止某些函数被内联时,我才会将所有类实现放在 .inl 文件中,或者在 .cpp 文件中,如果inline关键字可能强烈建议编译器内联某些函数,当然,事实并非如此。我确实希望库中的所有函数定义都驻留在 .cpp 文件中,但由于访问器方法在整个库中广泛使用,因此我必须确保它们在引用时内联,而不是调用。

因此,在这方面,我的问题是:

  1. 用 标记模板函数的定义是否有意义inline鉴于我最近了解到的事实here https://stackoverflow.com/questions/11416747/multiple-definitions-of-a-non-template-class-vs-a-template-class,无论它是否标记为内联,编译器都会自动将其限定为内联inline or not?

  2. And 最重要的是,因为我想收集模板类的所有成员函数的定义一起在一个文件中,最好是 .inl 或 .cpp(在 .cpp 的情况下使用显式实例化)still能够提示编译器(MSVC 和 GCC)应该内联哪些函数and这不应该,确定这样的事情是否可以通过模板函数实现,我怎样才能实现这个目标,或者,如果真的没有办法(我希望有),最佳的折衷方案是什么?

----------

EDIT1:我知道inline关键字只是建议编译器内联函数。

EDIT2:我确实知道。我喜欢向编译器提出建议。

EDIT3:我还是知道的。这不是问题的重点。

----------

鉴于一些新的信息,还有第三个问题与第二个问题同时出现。

3.如果现在的编译器如此聪明,他们可以更好地选择应该内联哪些函数以及应该调用哪些函数and能够进行链接时代码生成和链接时优化,这有效地允许他们在链接时查看位于 .cpp 的函数定义,以决定其内联或调用的命运,那么也许一个好的解决方案就是简单地移动所有定义到各自的 .cpp 文件中?

----------

那么结论是什么呢?

首先,我感谢 Daniel Trebbien 和 Jonathan Wakely 的结构化且有理有据的回答。两者都投了赞成票,但必须只选择一个。然而,给出的答案都没有为我提供可接受的解决方案,因此所选择的答案恰好是对我做出最终决定稍有帮助的答案,接下来将向感兴趣的人解释其详细信息。

好吧,由于我一直更看重代码的性能,而不是维护和开发的方便程度,因此在我看来,最可接受的折衷方案是移动每个的所有访问器方法和其他轻量级成员函数。将模板类放入相应标头包含的 .inl 文件中,并用以下标记标记这些函数inline尝试为编译器提供良好的提示(或内联强制的关键字),并将其余函数移至相应的 .cpp 文件中。

将所有成员函数定义都放在 .cpp 文件中会阻碍轻量级函数的内联,同时会引发链接时优化的一些问题,正如 MSVC 的 Daniel Trebbien(在较早的开发阶段)和 GCC 的 Jonathan Wakely 所确定的那样(目前的发展阶段)。将所有函数定义都放在头文件(或 .inl 文件)中并不比将每个类的实现分类到 .inl 和 .cpp 文件中的总体好处加上此决定的额外副作用:它将确保只有原始访问器方法的代码对库的客户端可见,而更多有趣的东西隐藏在二进制文件中(确保这不是主要原因,但是,对于熟悉软件库的任何人来说,这一点都是显而易见的)。任何不需要由库的包含文件公开并由其类私有使用的轻量级成员函数都可以在该类的 .cpp 文件中进行定义,而其声明/定义则包含inline鼓励函数的内联状态(尚不知道关键字是否应该出现在两个位置,或者在这种特殊情况下只出现在一个位置)。


简而言之:将模板代码放在头文件中。使用特定于编译器的forceinline or noinline如果优化器未能就内联做出正确的决定,则使用关键字。


您可以而且应该将模板成员的定义放入头文件中。这确保编译器在发现实际模板参数是什么时可以在使用时访问定义,并且能够执行隐式实例化。

The inline关键字对模板的影响很小,因为模板函数已经免除了单一定义要求(单一定义规则仍然要求所有定义相同)。它向编译器提示该函数应该被内联。您可以省略它,作为编译器不要内联该函数的提示。所以就这样使用它。但优化器仍会考虑其他因素(函数大小)并自行选择内联。

有些编译器有特殊的关键字,比如__attribute__(always_inline) or __declspec(noinline)覆盖优化器的选择。

不过,大多数情况下,编译器足够聪明,不会内联“作为函数调用更有意义的复杂代码”。您不必担心它,只需让优化器完成它的工作即可。

便携式内联控制没有什么好处,因为内联的权衡是非常特定于平台的。优化器应该已经意识到这些特定于平台的权衡,如果您确实觉得需要覆盖编译器的选择,请在每个平台的基础上进行操作。

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

跨文件的代码组织必须处理模板函数和内联 的相关文章

  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • 从 MVC 迁移到 ASP.NET Core 3.1 中的端点路由时,具有角色的 AuthorizeAttribute 不起作用

    我正在尝试将我的项目从 UseMVC asp net core 2 2 兼容样式 升级到 UseEndpoint Routing 并且我的所有请求都被重定向到我的验证失败页面 它与声明有关 如果我删除 Authorize Roles Adm
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • IronPython:没有名为 json 的模块

    我安装了 IronPython 我的 python 文件如下所示 import sys print sys version import json 运行它的代码 var p Python CreateEngine var scope p C
  • 当前的 c++ 工作草案与当前标准有何不同

    通过搜索该标准的 PDF 版本 我最终找到了这个链接C 标准措辞草案 http www open std org jtc1 sc22 wg21 docs papers 2012 n3376 pdf从 2011 年开始 我意识到我可以购买最终
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • 在 2D 中将一个点旋转另一个点

    我想知道当一个点相对于另一个点旋转一定角度时如何计算出新的坐标 我有一个块箭头 想要将其相对于箭头底部中间的点旋转角度 theta 这是允许我在两个屏幕控件之间绘制多边形所必需的 我无法使用和旋转图像 从我到目前为止所考虑的情况来看 使问题
  • Qt 创建布局并动态添加小部件到布局

    我正在尝试在 MainWindow 类中动态创建布局 我有四个框架 它们是用网格布局对象放置的 每个框架都包含一个自定义的 ClockWidget 我希望 ClockWidget 对象在调整主窗口大小时相应地调整大小 因此我需要将它们添加到
  • 基于xsd模式生成xml(使用.NET)

    我想根据我的 xsd 架构 cap xsd 生成 xml 文件 我找到了这篇文章并按照说明进行操作 使用 XSD 文件生成 XML 文件 https stackoverflow com questions 6530424 generatin
  • 无法将类型“System.IO.Stream”隐式转换为“Java.IO.InputStream”

    我提到了一些类似的问题 但没有一个涉及IO 当我使用时 我在java中使用了相同的代码Eclipse 那次就成功了 但现在我尝试在中使用这段代码Mono for Android C 它不起作用 我正在尝试运行此代码来创建一个InputStr
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 尚未处理时调用 Form 的 Invoke 时出现 ObjectDisposeException

    我们得到一个ObjectDisposedException从一个电话到Invoke在尚未处理的表格上 这是一些演示该问题的示例代码 public partial class Form2 Form void Form2 Load object
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • WinRT 定时注销

    我正在开发一个 WinRT 应用程序 要求之一是应用程序应具有 定时注销 功能 这意味着在任何屏幕上 如果应用程序空闲了 10 分钟 应用程序应该注销并导航回主屏幕 显然 执行此操作的强力方法是在每个页面的每个网格上连接指针按下事件 并在触
  • 使用 Crypto++ 获取 ECDSA 签名

    我必须使用 Crypto 在变量中获取 ECDSA 签名 我在启动 SignMessage 后尝试获取它 但签名为空 我怎样才能得到它 你看过 Crypto wiki 吗 上面有很多东西椭圆曲线数字签名算法 http www cryptop
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder

随机推荐

  • 使用 sklearn 通过 Keras 数据生成器绘制混淆矩阵

    Sklearn 明确定义了如何使用自己的分类模型绘制混淆矩阵plot confusion matrix https scikit learn org stable auto examples model selection plot con
  • componentDidUpdate 与 componentDidMount

    当满足以下条件时 我需要确保输入元素获得焦点 DOM 可用 并且属性发生了变化 问题 我需要将我的代码放入两个中吗componentDidUpdate and componentDidMount要不就componentDidUpdate就足
  • 如何在轴标签和图例中的下标中写入文本?

    我有以下轴标签和图例 plt ylabel ratio 2 plt xlabel n 1 plt legend alpha 1 alpha 2 loc best shadow True 在公式周围加上美元符号 plt xlabel n 1
  • 使用 webdriver 与可爱的编辑器交互

    有谁知道我如何使用 webdriver 与可爱的编辑器交互 我想清除文字 下面的代码不起作用 driver switchTo frame 0 driver switchTo activeEle
  • 是否可以在用户不与网络交互的情况下播放音频?我该怎么做呢? [复制]

    这个问题在这里已经有答案了 我需要我的网页在用户不与页面交互的情况下播放音频剪辑 我知道用户体验很差 不应该这样做 但这就是我的客户所要求的 我也知道浏览器已经阻止了这个功能 所以如果有人能给我建议如何 破解 这个规则 例如事件 我将不胜感
  • 如何在 Sphinx 运行时预处理源文件?

    我已经为我的项目设置了 Sphinx 文档 并希望提取源文件的文档字符串并将它们嵌入到最终文档中 不幸的是 Sphinx 不支持源文件的语言 VHDL VHDL 似乎没有 Sphinx 域 所以我的想法如下 挂钩 Sphinx 运行并在 S
  • 如何在maatwebsite中获取excel数组

    我正在尝试使用最新版本将 Excel 文件转换为数组Laravel Excel https github com Maatwebsite Laravel Excel 3 1 9 下面的代码将下载该文件 return Excel downlo
  • 一个图例的两个独特标记符号

    我想在图例下的 红色实心圆圈 符号旁边添加一个 红色实心正方形 符号 我该如何实现这一目标 我更喜欢坚持使用 pyplot 而不是 pylab 下面是我一直在使用的代码 fig plt figure ax1 fig add axes 0 1
  • 条件逻辑在默认的knockout.js 2.0模板引擎下工作吗?

    下面的条件不适用于我的默认模板与 knockout js 2 0 它只是写出 IF 语句 span if data app viewModel admin home paging page span span else a href a i
  • CPU 总使用率 - 多核系统

    我正在使用 xen 并与xen top我得到了 CPU 总使用率的百分比 NAME STATE CPU sec CPU MEM k MEM MAXMEM k MAXMEM VCPUS NETS NETTX k NETRX k VBDS VB
  • 日期时间差异返回正确的月份甚至年份?

    是否有任何内置函数如何以比仅天数更好的方式获取 DateTime 对象之间的差异 我的意思是 1 个月零 23 天 我发现由于每个月的天数 闰年等不同 计算起来非常困难 谢谢 看一下野田时间 http noda time googlecod
  • “Typemock Isolator”如何模拟静态方法?

    正如你们中的一些人所知 通常不可能在 net 中模拟静态方法 通过模拟 我的意思是用具有相同签名的另一个方法替换类中的方法 通常用于测试目的 用于模拟方法的两种主要方法是将其声明为虚拟方法或在接口中定义它 net 静态方法不允许使用这两种方
  • Chrome“无法拖动”图标会干扰鼠标悬停事件,我该如何防止这种情况?

    下面是一些使用 JavaScript 创建一堆 div 元素来充当像素的代码 我为 mouseover 事件添加了一个事件侦听器 并检查鼠标是否被按下 如果按下鼠标 我会更改该像素的颜色 最终结果是一个简单的绘图函数 我相信使用 HTML5
  • Entity Framework Core:获取所有表的列表

    如何获取数据库上下文中 Entity Framework Core 中所有表的列表 以下答案适用于 Entity Framework 5 中的早期版本 我们目前使用的是 EF Core 3 如何获取 EF 5 中所有实体的列表 https
  • 在 Propel 1.5 中执行多个条件的连接

    这个问题是从问题而来的here https stackoverflow com questions 6877226 rewriting not in sub select as join for propel and here https
  • 带有复杂编辑器的 JTable

    我有许多用于 JTable 的自定义编辑器 可以轻描淡写地说 其可用性 尤其是在使用键盘进行编辑方面 缺乏可用性 主要原因是我的编辑器总是在与此类似 尽管通常更复杂 的情况下创建 Override public Component getT
  • 从 SELECT 插入但更改一列?

    想知道是否有一种方法可以将行从另一个表插入到另一个表中 但一列除外 对于有限数量的列来说 这当然很容易 但是当列数增加时 列出所有列会有点烦人 我在想一些事情 Insert into table select replace col1 wi
  • Autofac。如何使用自定义方法(属性)来解析某些接口?

    我有以下接口 public interface IConfigurationProvider
  • Opera 跨源资源共享

    有人找到了 Opera 关于跨源资源共享的解决方法吗 我想做一个跨域XmlHttpRequest从我放置在 bar com 上的脚本到我的域 foo com The standard http www w3 org TR cors 目前为止
  • 跨文件的代码组织必须处理模板函数和内联

    我正在维护一个大型模板类库 它们基于以下任意一个执行代数计算float or double类型 许多类都有访问器方法 getter 和 setter 和其他运行少量代码的函数 因此当编译器找到它们的定义时 需要将这些函数限定为内联 相比之下