c++ - 创建模板函数库

标签 c++ templates

我一直在开发一个主要包含模板函数的库,并设法以下列方式(在某种程度上)使事情井井有条:

// MyLib.h
class MyLib
{
  template<class T>
  static void Func1()
  {
  }

  template<class T>
  static void Func2()
  {
  }
};

显然调用会像这样:

MyLib::Func1();

如您所见,随着添加的功能越来越多,这会变得非常难看。至少,我想把它分成不同的文件!

我最初考虑在 MyLib 命名空间中的单独文件中定义批量函数,然后使用 MyLib.h 来整合所有这些函数,但我一直收到大量链接器错误 - 当然,如果有人推荐,我可以仔细研究一下这种方法。

有什么想法吗?

PS:由于这些函数中的大多数都有不同的目标,因此将它们分组到我们实例化对象的类下是没有意义的。我在这里使用了一个 class,所以我不必担心定义函数的顺序(MyLib 中的函数之间也存在相互依赖性).

链接器错误:

所以基本结构是这样的:我有两个编译成静态库的类(比如 A 和 B)和一个运行这些类实例的主应用程序。这些类 A 和 B 使用 MyLib 中的函数。当 A 和 B 正在编译时,我收到 LNK4006 警告,指出属于 MyLib 的符号已经在项目的 OBJ 文件中定义它忽略了它。

当它归结为应用程序时,它变成了一个 LNK2005 错误,表明它已经在 A 和 B 的 OBJ 文件中定义。

更新: 谢谢Mike & Mathieu对于内联 想法 - 这就是问题所在!

除了一个问题:我有一些我明确指定的模板函数,这些函数导致已定义错误(LNK2005):

template<class t> int Cvt(){}
template<> int Cvt<unsigned char>(){return 1;}
template<> int Cvt<char>(){return 2;}
template<> int Cvt<unsigned short>(){return 3;}

有什么想法吗?

结论:

通过在单独的文件中定义模板函数解决了显式特化问题 - 感谢您的帮助!

最佳答案

与使用静态方法的类相比,您应该更喜欢命名空间:

  • 命名空间为您提供了在多个文件之间共享的可能性,每个逻辑组方法一个
  • namespace 可以省略:因为 ADL 启动或 using myNamespace::MyFunc;(注意:编写 using myNamespace; 是不好的做法,你应该避免这种做法)

现在,让我们谈谈组织:

  • 最好让文件层次结构隐藏命名空间层次结构 [1]
  • 按逻辑组拆分您的方法是一种很好的做法,这样用户就不必仅仅因为他想要打印 Hello, World! 就必须包括整个世界,商品标题可以提供帮助(即,为懒惰的程序员使用的一堆包含的 header )

[1] 我的意思是:

#include "lib/string/manip.hpp"    // Okay, this files come from "lib"

int main(int argc, char* argv[])
{
  std::string s;
  lib::string::manip(s);           // Same hierarchy, easy to remember the header
  return 0;
}

一个激励人心的例子? Boost 做到了(使用商品 header )。

更重要的是,这不会花费太多:只需将 class 替换为 namespace 并删除 static 关键字,就这些了。<​​/p>

对于链接器问题:所有未模板化的方法都应声明为 inline(尽量避免它,除非它们是单行代码)或在 header 之外定义(在单独的 .cpp 文件)。

更新:

模板特化的问题是您最终定义了一个现在“正常”的方法:一旦您修复了每个参数,就不再有任何模板。因此,解决方案就像您对普通函数所做的那样:在头文件中声明并在源文件中定义(因此只有一次)。

更具体地说明这个奇怪的错误:C++ 的问题是每个源文件都是独立编译的:预处理器将采用包含并实际创建一个包含每个包含文件的文本文件(在order),最后是你的来源。编译器获取此文件并生成一个“.o”文件(用于 gcc)。然后链接器开始尝试从所有这些“.o”文件中实际创建一个库(或二进制文件),它检查每个方法是否只定义一次,否则它将如何在多个定义之间进行选择(不幸的是没有检查它们是否等价...) ?

虽然模板方法和类有一个特殊的允许,它会(随机地)在所有实例化中选择一个(每个模板参数组合一个实例化)。当然,这是假设所有这些都是相同的,你最终可能会因为这样的事情而头疼不已:

// foo.h
template <class T> int foo(T) { return 10; }

// foo.cpp
#include "foo.h"

char a;
std::cout << foo(a) << std::endl;

// bar.cpp
#include "foo.h"

template <> int foo<char>(char) { return 20; }

char b;
std::cout << foo(b) << std::endl;

这两行将打印相同的输出,但不知道是 10 还是 20,并且可能会在构建之间发生变化!!!

关于c++ - 创建模板函数库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2117536/

相关文章:

c++ - 为什么 std::optional::value() &&;返回 &&?

python - 为 vim 编译 YouCompleteMe 时出错

c++ - 将 C 结构转换为 C++ 类

c++ - 分配 vector 值

c++ - DuplicateHandle 的代价

c++ - 为什么这个 C++ 模板代码不能编译?

c++ - 函数重载和模板

c++ - 部分类模板特化,C++

c++ - 传递本地创建的 lambda 用于回调,然后超出范围

c++ - 推导函数参数包的模板参数是否有缺陷