成员函数模板放在哪里

2024-01-11

C++ 中经常让我感到沮丧的一个方面是决定模板在头文件(传统上描述接口)和实现 (.cpp) 文件之间的位置。模板通常需要进入标头,公开实现,有时还需要引入以前只需要包含在 .cpp 文件中的额外标头。我最近再次遇到这个问题,下面显示了一个简化的示例。

#include <iostream> // for ~Counter() and countAndPrint()

class Counter
{
  unsigned int count_;
public:
  Counter() : count_(0) {}
  virtual ~Counter();

  template<class T>
  void
  countAndPrint(const T&a);
};

Counter::~Counter() {
    std::cout << "total count=" << count_ << "\n";
}

template<class T>
void
Counter::countAndPrint(const T&a) {
  ++count_;
  std::cout << "counted: "<< a << "\n";
}

// Simple example class to use with Counter::countAndPrint
class IntPair {
  int a_;
  int b_;
public:
  IntPair(int a, int b) : a_(a), b_(b) {}
  friend std::ostream &
  operator<<(std::ostream &o, const IntPair &ip) {
    return o << "(" << ip.a_ << "," << ip.b_ << ")";
  }
};

int main() {
  Counter ex;
  int i = 5;
  ex.countAndPrint(i);
  double d=3.2;
  ex.countAndPrint(d);
  IntPair ip(2,4);
  ex.countAndPrint(ip);
}

请注意,我打算使用我的实际类作为基类,因此使用虚拟析构函数;我怀疑这很重要,但我把它留在柜台以防万一。上述结果的输出是

counted: 5
counted: 3.2
counted: (2,4)
total count=3

Now Counter的类声明可以全部放在头文件中(例如 counter.h)。我可以将需要 iostream 的 dtor 的实现放入 counter.cpp 中。但是成员函数模板该怎么办countAndPrint(),它也使用iostream?它在 counter.cpp 中没有用,因为它需要在编译的 counter.o 之外实例化。但是将它放在 counter.h 中意味着任何包含 counter.h 的内容也依次包含 iostream,这似乎是错误的(我承认我可能必须克服这种厌恶)。我还可以将模板代码放入单独的文件中(counter.t?),但这对于代码的其他用户来说会有点令人惊讶。Lakos https://rads.stackoverflow.com/amzn/click/com/0201633620并没有像我想要的那样真正深入研究这个问题,并且C++ FAQ http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13没有进入最佳实践。所以我追求的是:

  1. 有没有其他方法可以将代码划分为我建议的代码?
  2. 在实践中,什么最有效?

经验法则(其原因应该很清楚)。

  • 私有成员模板应在 .cpp 文件中定义(除非它们需要由类模板的朋友调用)。
  • 非私有成员模板应在标头中定义,除非它们被显式实例化。

您通常可以通过使名称具有相关性来避免包含大量标头,从而延迟查找和/或确定其含义。这样,您仅在实例化时才需要完整的标头集。举个例子

#include <iosfwd> // suffices

class Counter
{
  unsigned int count_;
public:
  Counter() : count_(0) {}
  virtual ~Counter();

  // in the .cpp file, this returns std::cout
  std::ostream &getcout();

  // makes a type artificially dependent
  template<typename T, typename> struct ignore { typedef T type; };

  template<class T>
  void countAndPrint(const T&a) {
    typename ignore<std::ostream, T>::type &cout = getcout();
    cout << count_;
  }
};

这就是我用来实现使用 CRTP 的访问者模式的方法。最初看起来像这样

template<typename Derived>
struct Visitor {
  Derived *getd() { return static_cast<Derived*>(this); }
  void visit(Stmt *s) {
    switch(s->getKind()) {
      case IfStmtKind: {
        getd()->visitStmt(static_cast<IfStmt*>(s));
        break;
      }
      case WhileStmtKind: {
        getd()->visitStmt(static_cast<WhileStmt*>(s));
        break;
      }
      // ...
    }
  }
};

由于这些静态转换,这将需要所有语句类的标头。所以我已经使类型成为依赖的,然后我只需要前向声明

template<typename T, typename> struct ignore { typedef T type; };

template<typename Derived>
struct Visitor {
  Derived *getd() { return static_cast<Derived*>(this); }
  void visit(Stmt *s) {
    typename ignore<Stmt, Derived>::type *sd = s;
    switch(s->getKind()) {
      case IfStmtKind: {
        getd()->visitStmt(static_cast<IfStmt*>(sd));
        break;
      }
      case WhileStmtKind: {
        getd()->visitStmt(static_cast<WhileStmt*>(sd));
        break;
      }
      // ...
    }
  }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

成员函数模板放在哪里 的相关文章

  • 将复选框添加到 UniformGrid

    我正在尝试将复选框动态添加到 wpf 中的统一网格中 但看起来网格没有为它们分配足够的空间 所以它们都有点互相重叠 这就是我将它们添加到后面的代码中的方法 foreach string folder in subfolders PathCh
  • 检查两个数是否是彼此的排列?

    给定两个数字 a b 使得 1 例如 123 是 312 的有效排列 我也不想对数字中的数字进行排序 如果您指的是数字的字符 例如 1927 和 9721 则 至少 有几种方法 如果允许排序 一种方法是简单地sprintf将它们放入两个缓冲
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • ASP.NET Core Serilog 未将属性推送到其自定义列

    我有这个设置appsettings json对于我的 Serilog 安装 Serilog MinimumLevel Information Enrich LogUserName Override Microsoft Critical Wr
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • 使用 libcurl 检查 SFTP 站点上是否存在文件

    我使用 C 和 libcurl 进行 SFTP FTPS 传输 在上传文件之前 我需要检查文件是否存在而不实际下载它 如果该文件不存在 我会遇到以下问题 set up curlhandle for the public private ke

随机推荐

  • Tkinter 中的按钮命令

    我正在尝试使用 tkinter 进行一次文本冒险 并且正在慢慢地将一些东西组合在一起 我试图显示从一个房间到另一个房间的命令 但即使按钮出现 当我按下它们时什么也没有发生 game py usr bin python coding utf
  • 在 Kibana 4 中向导航栏添加页面

    我正在尝试向 Kibana 4 添加欢迎 介绍页面 并且需要修改导航菜单 我在 src kibana plugins kibana kibana html 找到了导航源 html 文档 但无法弄清楚选项卡名称是从哪里注入的 这是进行调用的列
  • 使用 VS 11、.NET 4.5 和实体框架时生成错误

    在 Visual Studio 2010 中 我的解决方案使用 NET 4 2 实体框架 2011 年 6 月 CTP 因此我可以在实体框架中使用空间类型 当我升级到 Visual Studio 11 Beta 时 由于 4 2 和 4 5
  • 异常未传播到 Apache Camel 中的错误处理程序

    我有一条定义 doTry doCatch 块的路线 当在 doCatch 块中处理异常时 我希望将其传播到错误处理程序 以确保消息在本地处理后添加到死信队列中 问题是我无法让错误处理程序的传播正常工作 defaultErrorHandler
  • 将@interface放入.m文件中的逻辑是什么? [复制]

    这个问题在这里已经有答案了 可能的重复 h 和 m 文件中 interface 定义的区别 https stackoverflow com questions 3967187 difference between interface def
  • Android 5.0:如何更改最近使用的应用程序标题颜色?

    我正在使用 AppCompat 并且我的主题正在扩展Theme AppCompat Light DarkActionBar 当我在 Android 5 Lollipop 中按下最近使用的应用程序按钮时 我的应用程序会出现dark标题而不是
  • “DoCmd.OutputTo acOutputQuery”正在删除查询

    我遇到了一个问题DoCmd OutputTo acOutputQuery第二次运行时删除查询本身 这个错误有任何解决方法 补丁吗 至少对我来说似乎是一个错误 回复 你的评论 您是否进行了文件复制 或者是否在两个数据库之间复制了对象 如果是第
  • 64位linux内核如何从ELF启动32位进程

    通过查看binfmt elf c https elixir bootlin com linux v3 5 source fs binfmt elf c在内核源代码中 我无法弄清楚内核 64 位 在生成 32 位进程与 64 位进程时有何不同
  • 性能:boost.compute vs. opencl C++ 包装器

    以下代码分别使用 boost compute 和 opencl C 包装器将两个向量相加 结果显示 boost compute 几乎比 opencl c 包装器慢 20 倍 我想知道我是否错过了使用 boost compute 或者它确实很
  • 如果 automountServiceAccountToken 设置为 false,Pod 服务帐户的用途是什么?

    服务帐户的 API 凭证通常挂载在 pod 中 如下所示 var run secrets kubernetes io serviceaccount token 此令牌允许 Pod 中的容器化进程与 API 服务器进行通信 Pod 服务帐户的
  • 尝试在 Google App Engine 上部署 node.js 时出错

    我在尝试部署时遇到错误Node js应用程序到 Google App Engine Node js运行时因 require 语句而崩溃 我有什么错吗 目录结构 app 协议 js应用程序 js 在文件 app js 中 var protoc
  • 如何以编程方式获取 iPhone 的 MAC 地址

    如何以编程方式获取 iPhone 的 MAC 地址和 IP 地址 NOTE从 iOS7 开始 您无法再检索设备 MAC 地址 将返回一个固定值而不是实际的 MAC 我不久前偶然发现的一件事 最初是从here http www iphoned
  • 我该如何解决此推送错误 - 从身份验证端点返回的 JSON 无效,但状态代码为 200?

    在这里问同样的问题后我仍然遇到这个问题 从 auth 端点返回的 JSON 无效 但状态代码为 200 https stackoverflow com questions 67082279 json returned from auth e
  • 如何仅从一列中选择不同的值

    我有记录如下 key name 1111 aa 1111 bb 2222 cc 我需要选择key and name当 的时候key价值是独特的 当我尝试时 select distinct key name from table 我得到了所有
  • 在c++中将hdf5文件读取到动态数组

    由于堆栈的大小限制 我正在尝试将大型 3D hdf5 文件读入动态数组 我尝试了几种不同的方法 但由于分段错误而失败 下面是显示我的问题的示例代码 我非常感谢一些帮助 This example was based on several ex
  • RestTemplateBuilder bean

    我的应用程序与不同的休息端点交互 每个端点都需要一个专门的 RestTemplate 对象 我正在使用 RestTemplateBuilder 创建每个 RestTemplate 对象 克隆 Spring Boot 提供的 RestTemp
  • AngularJS module.constant() :如何仅在模块内定义常量?

    在一个页面上 我有几个 Angular 模块 对于每个模块 我定义一个包含模块版本的常量 var module1 angular module module1 constant version 1 2 3 var module2 angul
  • 如何在 C++ 中维护指向父级的弱指针?

    是否有一种标准方法可以在 C 的子对象中维护指向父对象 使用共享指针创建 的弱指针 本质上 我需要实现以下内容 Class B Class A private B m b Class B public void SetParentPtr c
  • 正常关闭 IHostedService

    我正在尝试在 NET Core 中开发一个简单的 API 允许异步处理请求 请求发送至控制器 后台服务 IHostedService 上安排的工作 控制器返回 202 后台服务执行长时间运行的操作 由于应用程序将在 IIS 上运行 因此控制
  • 成员函数模板放在哪里

    C 中经常让我感到沮丧的一个方面是决定模板在头文件 传统上描述接口 和实现 cpp 文件之间的位置 模板通常需要进入标头 公开实现 有时还需要引入以前只需要包含在 cpp 文件中的额外标头 我最近再次遇到这个问题 下面显示了一个简化的示例