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

如何正确声明适配二元运算的C++ concept及相关问题咨询

问题1:如何修复二元运算concept的声明逻辑

你之前的两种实现错误原因如下:

  • 第一种方案直接比较Op和Ret(Arg1, Arg2)函数类型的相等性,但是可调用对象的类型远不止原生函数,还包括lambda、仿函数、std::function包装器等,这些类型和原生函数类型并不相同,因此匹配失败。
  • 第二种方案通过std::function包装后比较类型相等性同样错误,std::function可以兼容存储所有签名匹配的可调用对象,但不同来源的可调用对象包装后的std::function类型本身是相同的,且直接比较类型的逻辑无法覆盖隐式类型转换的场景,因此校验失败。

正确的实现应该使用C++标准库提供的std::invocable系列工具,根据你的需求有两种可选方案:

  1. 仅校验可调用性,不限制返回值类型:
// 注意:自定义concept必须放在自己的命名空间,不要放到std中
namespace utils {
template <typename Op, typename Arg1, typename Arg2>
concept binary_op = std::is_invocable_v<Op, Arg1, Arg2>;
}
  1. 同时校验调用返回值可以转换为指定类型,更适合你的快速幂场景(保证运算结果可以赋值给acc变量):
namespace utils {
template <typename Op, typename Ret, typename Arg1, typename Arg2>
concept binary_op_returnable = std::is_invocable_r_v<Ret, Op, Arg1, Arg2>;
}

对应的power函数可以改写为:

template <std::integral I, utils::binary_op_returnable<I, I, I> Op>
I power(I acc, I a, I n, Op op) {
  while (n-- != I{0}) {
    acc = op(acc, a);
  }
  return acc;
}

注意:不要向std命名空间添加自定义的非特化内容,这属于C++标准规定的未定义行为,你的补充版本将binary_op放到std命名空间是错误的。


问题2:为什么C++标准库没有内置固定元数的函数concept

主要有三个原因:

  1. 标准库已经提供了更通用的std::invocable、std::regular_invocable等concept(C++20起引入),完全可以满足固定元数的校验需求:校验一元函数就传入Op, T两个模板参数,校验二元函数就传入Op, T1, T2三个模板参数,无需单独封装固定元数的concept。
  2. 固定元数的函数定义过于模糊,很多可调用对象支持多重重载,既可以接受1个参数也可以接受多个参数,单独的“一元函数”“二元函数”concept无法覆盖这类场景,灵活性不足。
  3. 标准库的设计原则是优先提供通用基础组件,特定语义的封装交给用户根据业务场景自定义,避免过度设计导致的适用范围受限。

额外优化建议

如果你的快速幂后续要扩展到更通用的场景(比如运算对象不是整数),可以去掉std::integral的限制,或者将运算对象和计数用的整数类型分开定义,更符合《Elements of Programming》中的通用设计思路。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 15:06:04