为什么使用非类型模板参数? [复制]

2024-02-05

我读过很多问题和答案,但是这个问题 https://stackoverflow.com/questions/12550398/why-we-use-non-type-template-arguments最吸引我的眼球;它及其答案很有帮助,但我仍然觉得我没有完全理解使用非类型模板参数背后的用途和理论。他们提供了许多关于何时使用它的有用示例,但没有一个真正阐明非类型模板参数背后的理论。

我感兴趣的不是具体在示例中,而是更广泛地了解为什么我倾向于使用非类型模板参数而不是常规函数参数。

我知道它们是在编译时确定的,并且每个新调用都会创建一个具有非类型模板参数的确定值的新函数。那么,为什么我想要创建同一函数的许多不同实例,因为我只需将所需的参数输入到一个函数中,并且只用一个编译函数就可以得到相同的结果(据说)。

本质上,为什么我应该倾向于做#1,而不是#2,根据最后一节这一页 http://www.cplusplus.com/doc/tutorial/functions2 of cplusplus.com http://www.cplusplus.com?

#1:

template <class T, int N>
T fixed_multiply (T val)
{
  return val * N;
}

int main() {
  std::cout << fixed_multiply<int,2>(10) << '\n';
  std::cout << fixed_multiply<int,3>(10) << '\n';
}

#2:

template <class T>
T fixed_multiply (T val, int N)
{
  return val * N;
}

int main() {
  std::cout << fixed_multiply<int>(10, 2) << '\n';
  std::cout << fixed_multiply<int>(10, 3) << '\n';
}

此外,是否会有任何性能优势或类似优势?是否有任何常见应用程序可以从使用非类型模板参数中受益,或者这是在特定应用程序中使用的高科技参数以产生特定结果?

编辑:由于某种原因,这被标记为重复,第一段解释了我提出类似问题的原因。


当您希望(或需要)编译器在保持代码良好分解的同时进行某些编译时优化时,它们非常有用。我简单举几个例子:

分支消除

void doSomething(bool flag) {
  if (flag) {
    //whatever
  }
}

template <bool flag>
void doSomething() {
 if (flag) {
   //whatever
}

}

在上面的例子中,如果你总是知道flag在编译时调用时doSomething,那么就可以避免分支的成本,而无需手动创建doSomethingTrue and doSomethingFalse函数可能需要您重复很多代码。例如,当您想要在网络代码中的发送端和接收端之间分解代码,并且您的代码位于性能关键堆栈的深处时,此技巧非常有用。

避免动态内存管理

void someFunction(size_t size, float* inout) {
  std::vector<float> tmp(size);
  //do something with inout and tmp and then store result in inout
}

template <size_t N>
void someFunction(float *inout) {
  float tmp[N]; //or std::array if you like
  //do something with inout and tmp and store result in inout
}

在上面的示例中,如果第二个版本陷入关键循环内,它的性能会好得多。

允许特殊优化

考虑循环:

for (size_t i = 0; i < N; ++i) {
  //some arithmetic
}

如果编译器知道 N 是 4 或 8,它可能能够用等效的 SIMD 指令替换算术,或者至少比 N 是运行时参数时更智能地展开循环。这种事情在 GPU 编程 (CUDA) 领域很常见。

模板元编程

当您使用模板生成一些重要的代码时,有时您必须在编译时迭代某些内容。您需要模板非类型参数才能执行此操作。参数包和std::tuple这是一种常见的情况,但还有更多,这里很难举例说明。

要回答您的问题,如果您有选择,何时将某些内容设为模板参数:采用动态(运行时)参数的代码总是更灵活,因此您应该只将某些内容转换为模板参数,如果您可以使用性能大幅提升。另一方面,如果您发现自己在一组枚举上编写了很多重复的代码,那么您可能应该尝试使用模板进行分解。

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

为什么使用非类型模板参数? [复制] 的相关文章

  • 什么定义了类型的大小?

    ISO C 标准规定 sizeof char lt sizeof short lt sizeof int lt sizeof long 我在 BIT Linux mint 19 1 上使用 GCC 8 大小为long int is 8 我正
  • 如何使用 Entity Framework 和 Identity 解决对象处置异常 ASP.NET Core

    我正在尝试编写一个控制器 该控制器接收来自 AJAX 调用的请求并通过 DBContext 对数据库执行一些调用 但是 当我发出命令时var user await GetCurrentUserAsynch 在对 DBContext 的任何调
  • getline 之后返回到文件开头

    所以我已经从文件中读取了所有行 while getline ifile line logic 其中 ifile 是 ifstream line 是字符串 我的问题是我现在想再次使用 getline 并且似乎无法返回到文件的开头 因为运行 c
  • 在 WCF 上重用我的 PagedList 对象

    问题 我有一个自定义集合PagedList
  • C# 异步任务比同步慢

    你知道为什么同步斐波那契方法比异步 等待更快并且比异步任务更快吗 我在每个项目方法上都使用了异步 所以主要是这是一个非常糟糕的方法 Code static int FibonacciSync int number if number 0 r
  • 如何从不同的线程访问控件?

    如何从创建控件的线程以外的线程访问控件 避免跨线程错误 这是我的示例代码 private void Form1 Load object sender EventArgs e Thread t new Thread foo t Start p
  • 从内存流播放视频文件

    只是好奇看看这是否可能 我有一个 Windows 应用程序 它从我的电脑上的 avi 文件读取所有字节 然后将其存储在 byte 中 现在我的内存中有 avi 文件 我想直接从内存将其加载到某种视频播放器控件中 我尝试过使用 wmplaye
  • 为什么像 BindingList 或 ObservableCollection 这样的类不是线程安全的?

    我一次又一次发现自己必须编写 BindingList 和 ObservableCollection 的线程安全版本 因为当绑定到 UI 时 这些控件无法从多个线程更改 我想理解的是why情况就是这样 这是设计错误还是故意的 问题是设计一个线
  • std::make_pair 与浮点数组(float2,无符号整数)

    我有一个用 float2 unsigned int 对模板化的向量 例如 std vector
  • 检查两个函数或成员函数指针的签名是否相等

    我编写了一些代码来检查自由函数的签名是否等于成员函数的签名等 它比较提取的返回类型和函数参数 include
  • ASP.NET MVC 动作过滤器

    有谁知道即使在 CATCH 块中 ActionFilterAttribute 类的 OnResultExecuted 方法是否也会执行 ie CookiesActions public ActionResult Login Usuarios
  • 节点*链表中的下一个

    我是数据结构和算法的新手 我遇到了以下代码 typedef struct node int data node next 谁能告诉我为什么我们要声明节点 next next 不能声明为 int next 吗 因为你希望能够做到n gt ne
  • 从 C# 调用时无法识别 Powershell 命令

    这是这个的延续Question https stackoverflow com questions 66280000 powershell object returns null 66280138 noredirect 1 comment1
  • 如何禁用基于 ValidationRule 类的按钮?

    如何禁用基于 ValidationRule 类的 WPF 按钮 下面的代码可以很好地突出显示 TextBox
  • 应在堆栈上分配的最大数量

    我一直在寻找堆栈溢出有关应在堆栈上分配的最大内存量的指南 我看到了堆栈与堆分配的最佳实践 但没有关于应该在堆栈上分配多少以及应该在堆上分配多少的指南 有什么想法 数字可以作为指导吗 什么时候应该在堆栈上分配 什么时候应该在堆上分配 多少才算
  • 如何释放字符串未使用的容量

    我正在程序中处理很多字符串 这些字符串数据在读入我的程序后的整个生命周期内都不会改变 但由于 C 字符串保留了容量 因此浪费了大量肯定不会被使用的空间 我尝试释放这些空间 但没有成功 以下是我尝试过的简单代码 string temp 123
  • 基础设施 - 同步和异步接口和实现? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 在实现库 基础设施时 并且该 API 的用户希望同步和异步使用代码 我读到混合同步和异步并不是一个好主意 例如 同步实现包括等待异步实现 显然
  • 为什么 C++ 标准没有将 sizeof(bool) 定义为 1?

    Size of char signed char and unsigned char由 C 标准本身定义为 1 个字节 我想知道为什么它没有定义sizeof bool also C 03 标准 5 3 3 1 说 sizeof char s
  • 如何通过API退出Win32应用程序?

    我有一个使用 Win32 API 编写的 C Win32 应用程序 我希望强制它在其中一个函数中退出 有没有类似的东西Exit or Destroy or Abort 类似的东西会终止它吗 哎呀呀呀呀呀呀 不要做任何这些事情 exit 和
  • 创建进程默认浏览器

    我目前正在使用 ShellExecute 打开 在用户浏览器中打开 URL 但在 Win7 和 Vista 中遇到了一些麻烦 因为该程序作为服务运行提升 我想获取线程 id 因此 ShellExecute 无法获取线程 id 因此我开始使用

随机推荐