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

如何结合Lambda表达式使用boost::binary_traits?

问题描述

我尝试用boost::binary_traits获取仿函数的参数类型,这个方法对std::function有效,但对Lambda类型无效。

代码示例

#include <boost/functional.hpp>

template<typename Functor>
void foo(Functor&& f)
{
    boost::binary_traits<Functor>::first_argument_type a = 1; // 错误 C2528: 'abstract declarator': pointer to reference is illegal
}

void bar()
{
    auto func1 = [](int i, int j) { return j; };
    std::function<int(int, int)> func2 = [](int i, int j) { return j; };
    foo(func1);
    boost::binary_traits<decltype(func1)>::first_argument_type b = 1; // 错误 C2039: 'result_type': is not a member of 'bar::<lambda_227a80eb4d5d25e23ac8db99e4a9edf0>
    boost::binary_traits<decltype(func2)>::first_argument_type c = 1; // 正常
    boost::binary_traits<std::function<int(int, int)>>::first_argument_type d = 1; // 正常
}

我需要编写能让foo(func1)正常工作的foo函数,背景是要实现如下的accumulate函数,希望头文件里不用添加大量辅助模板让调用者可见:

template<typename Iterable, typename Functor>
inline auto accumulate(Iterable& input, Functor&& accumulator)
{
    boost::binary_traits<Functor>::first_argument_type output;
    std::for_each(
        std::begin(input),
        std::end(input),
        [&output, &accumulator](auto& m) { output = accumulator(output, m); });
    return output;
}

解决方案

核心原因

boost::binary_traits依赖仿函数类型暴露result_type、first_argument_type等嵌套类型,但C++原生Lambda不会自动生成这些类型;同时foo中直接用转发引用Functor&&实例化boost::binary_traits,会传入引用类型,这也是报错的原因之一。

实用解决方法

可以用C++17及以上的原生类型萃取工具替代Boost的旧特性,兼容Lambda和所有可调用对象,无需额外暴露辅助模板给调用者:

1. 修复foo函数

先实现通用的二元函数类型萃取器,兼容Lambda和std::function:

#include <type_traits>

// 通用二元函数类型萃取器
template<typename F, typename = void>
struct binary_function_traits {};

// 匹配包含operator()的类型(如Lambda、自定义仿函数)
template<typename F>
struct binary_function_traits<F, std::void_t<decltype(&F::operator())>> {
    // 提取operator()的类型
    using OpType = decltype(&F::operator());

    // 萃取成员函数的返回值和参数类型
    template<typename Ret, typename Class, typename Arg1, typename Arg2>
    struct extractor {
        using result_type = Ret;
        using first_argument_type = Arg1;
        using second_argument_type = Arg2;
    };

    // 适配Lambda的const版本operator()
    template<typename Ret, typename Class, typename Arg1, typename Arg2>
    struct extractor<Ret(Class::*)(Arg1, Arg2) const> {
        using result_type = Ret;
        using first_argument_type = Arg1;
        using second_argument_type = Arg2;
    };

    using traits = extractor<OpType>;
    using result_type = typename traits::result_type;
    using first_argument_type = typename traits::first_argument_type;
    using second_argument_type = typename traits::second_argument_type;
};

// 适配std::function的特化(可选,通用版已支持)
template<typename Ret, typename Arg1, typename Arg2>
struct binary_function_traits<std::function<Ret(Arg1, Arg2)>> {
    using result_type = Ret;
    using first_argument_type = Arg1;
    using second_argument_type = Arg2;
};

// 便捷别名,自动移除引用和CV限定符
template<typename F>
using binary_first_arg = typename binary_function_traits<std::remove_cvref_t<F>>::first_argument_type;

// 修复后的foo函数
template<typename Functor>
void foo(Functor&& f)
{
    binary_first_arg<Functor> a = 1;
}

2. 修复目标accumulate函数

用萃取工具或std::invoke_result推导输出类型,实现更简洁:

#include <type_traits>
#include <algorithm>

template<typename Iterable, typename Functor>
inline auto accumulate(Iterable& input, Functor&& accumulator)
{
    using IterValue = typename std::iterator_traits<decltype(std::begin(input))>::value_type;
    // 推导accumulator的返回类型,兼容所有可调用对象
    using OutputType = std::invoke_result_t<Functor, IterValue, IterValue>;

    OutputType output{}; // 值初始化
    std::for_each(
        std::begin(input),
        std::end(input),
        [&output, &accumulator](auto& m) { output = accumulator(output, m); });
    return output;
}

关键注意点

  • 必须用std::remove_cvref_t移除转发引用的引用和CV限定符,避免萃取工具处理引用类型
  • Lambda的operator()默认是const的,萃取时要匹配该版本
  • C++20可进一步用std::invocable概念做编译期检查,增强代码健壮性

内容的提问来源于stack exchange,提问作者H.v.M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 19:22:40