作为模板参数与参数传递的 C++ 函数

标签 c++ function templates

在 C++ 中,有两种方法可以将一个函数传递给另一个看起来等价的函数。

#include <iostream>

int add1(int i){ return i+1; }
int add2(int i){ return i+2; }

template <int (*T)(int) >
void doTemplate(int i){
    std::cout << "Do Template: " << T(i) << "\n";
}

void doParam(int i, int (*f)(int)){
    std::cout << "Do Param: " << f(i) << "\n";
}

int main(){
    doTemplate<add1>(0);
    doTemplate<add2>(0);

    doParam(0, add1);
    doParam(0, add2);
}

doTemplate 接受一个函数作为模板参数,而 doParam 接受它作为一个函数指针,它们似乎都给出相同的结果。

使用每种方法之间的权衡是什么?

最佳答案

基于模板的版本允许编译器内联调用,因为函数的地址在编译时是已知的。显然,缺点是函数的地址必须在编译时已知(因为您将它用作模板参数),有时这可能是不可能的。

这将我们带到第二种情况,函数指针可能仅在运行时确定,因此编译器无法执行内联,但让您可以灵活地在运行时确定函数被称为:

bool runtimeBooleanExpr = /* ... */;
doParam(0, runtimeBooleanExpr ? add1 : add2);

但是请注意,还有第三种方式:

template<typename F>
void doParam(int i, F f){
    std::cout << "Do Param: " << f(i) << "\n";
}

这为您提供了更大的灵 active ,并且仍然具有在编译时知道将调用什么函数的优势:

doParam(0, add1);
doParam(0, add2);

而且它还允许传递任何可调用对象而不是函数指针:

doParam(0, my_functor());

int fortyTwo = 42;
doParam(0, [=] (int i) { return i + fortyTwo; /* or whatever... */ }

为了完整性,还有第四种方式,使用std::function:

void doParam(int x, std::function<int(int)> f);

它具有相同级别的通用性(因为您可以传递任何可调用对象),但也允许您在运行时确定可调用对象 - 很可能会带来性能损失,因为(再一次)内联变得不可能对于编译器。

有关最后两个选项的进一步讨论,另请参阅 this Q&A on StackOverflow .

关于作为模板参数与参数传递的 C++ 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16440029/

相关文章:

C++ 替代模板化数据成员

c++ - 这段代码如何从元组中提取参数?

c++ - 在全局/函数范围内声明变量。堆栈差异?

c++ - 如何修复 std::stoi 中的 "std::invalid_argument"

c++ - 在 Visual Studio for C++ 中使用通过 VCPKG 安装的 Qt5

c++ - 当在 C++11 中使用带有两个声明的 auto 时会发生什么?

Javascript - 让函数告诉调用者函数何时完成

c++ - 如果我不应该使用 unsigned,我该如何在类型级别指定一个非负数?

php - 从 php 中的数组构造 javascript

c++ - 将指向类成员的指针作为模板参数传递