You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++可变参数模板函数中如何调用带默认参数的函数?

问题:如何在可变参数模板函数中使用被调用函数的默认参数?

我正在学习可变参数模板函数,编写了一个timeIt函数用于接收另一个函数并调用它,代码如下:

#include <chrono>
#include <iostream>
#include <string>

std::string leftPad(std::string str, unsigned len, char c = ' ') {
  if (str.length() >= len)
    return str;
  return std::string(len - str.length(), c) + str;
}

template <typename T, typename... Args, typename... Args2>
auto timeIt(T (*func)(Args...), Args2... args) {
  namespace ch = std::chrono;
  auto start = ch::high_resolution_clock::now();
  func(args...);
  auto end = ch::high_resolution_clock::now();
  return ch::duration_cast<ch::microseconds>(end - start).count();
}

int main() {
  std::cout << timeIt(&leftPad, "foo", 10) << std::endl;
  return 0;
}

这段代码只有显式传入最后一个参数' '时才能编译通过(比如timeIt(&leftPad, "foo", 10, ' ')),请问是否有办法直接使用leftPad函数的默认参数?


解决方案

核心原因

默认参数不属于函数签名的一部分,当你取&leftPad的地址时,编译器只能匹配到签名为std::string(std::string, unsigned, char)的函数指针,模板推导会要求传入三个参数,因此直接省略默认参数会导致编译失败。

方法1:用Lambda表达式包裹调用(推荐)

Lambda可以在内部直接利用函数的默认参数,同时我们可以修改timeIt使其支持任意可调用对象(包括Lambda、仿函数等),通用性更强:

修改后的timeIt模板:

#include <functional> // 需包含std::invoke的头文件

template <typename Func, typename... Args>
auto timeIt(Func func, Args... args) {
  namespace ch = std::chrono;
  auto start = ch::high_resolution_clock::now();
  std::invoke(func, args...); // std::invoke支持所有可调用对象的调用
  auto end = ch::high_resolution_clock::now();
  return ch::duration_cast<ch::microseconds>(end - start).count();
}

调用方式:

int main() {
  // Lambda内部调用leftPad时自动使用默认参数' '
  std::cout << timeIt([](){ return leftPad("foo", 10); }) << std::endl;
  return 0;
}

方法2:用std::bind绑定默认参数

如果坚持使用函数指针的方式,可以用std::bind把默认参数绑定到函数上,生成一个新的可调用对象:

#include <functional>

int main() {
  auto bound_leftPad = std::bind(leftPad, std::placeholders::_1, std::placeholders::_2, ' ');
  std::cout << timeIt(bound_leftPad, "foo", 10) << std::endl;
  return 0;
}

这种方式需要注意std::bind的使用细节,可读性不如Lambda直观。

方法3:为函数添加重载版本

手动为leftPad添加一个不带第三个参数的重载函数,这样编译器可以匹配到对应的函数指针:

std::string leftPad(std::string str, unsigned len) {
  return leftPad(str, len, ' '); // 调用带默认参数的版本
}

之后就可以直接调用timeIt(&leftPad, "foo", 10),编译器会匹配到新的重载函数。


内容的提问来源于stack exchange,提问作者felipe0o0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 05:02:04