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

如何创建带上下文捕获参数的boost::range::transform重载版本?

解决Boost 1.55 + VS2010中带引用捕获lambda与transform适配器的编译问题

首先,咱们来拆解你遇到的编译失败原因:

在VS2010的实现中,带捕获的lambda(尤其是引用捕获)会被编译器禁用赋值运算符(相当于operator=被delete)。而Boost 1.55的transformed适配器内部会尝试对存储的函数对象执行赋值操作,当它处理带引用捕获的lambda时,就会触发非法赋值构造函数的编译错误。无捕获的lambda可以隐式转换为函数指针,且其赋值构造是合法的,所以能正常运行。

接下来,咱们实现你想要的、类似std::lower_bound的带额外参数的transformed重载,不用写繁琐的完整仿函数:

步骤1:定义二元函数包装器

这个包装器会把你的二元lambda(接收range元素+额外参数)转换成transformed需要的一元函数对象:

#include <boost/range/adaptors.hpp>
#include <utility> // 用于std::forward

// 如果VS2010没有std::decay,自己实现简化版本
template <typename T>
struct decay
{
    typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;
};

template <typename Func, typename Arg>
struct BinaryTransformWrapper
{
    Func func;
    Arg arg;

    // 构造函数,完美转发参数
    BinaryTransformWrapper(Func&& f, Arg&& a) 
        : func(std::forward<Func>(f)), arg(std::forward<Arg>(a)) {}

    // 一元调用运算符,把range元素和额外参数传给二元lambda
    template <typename T>
    auto operator()(T&& val) -> decltype(func(std::forward<T>(val), arg))
    {
        return func(std::forward<T>(val), arg);
    }
};

步骤2:重载transformed适配器

我们把重载函数放到boost::adaptors命名空间里,这样就能像原生transformed一样用管道语法:

namespace boost { namespace adaptors {

    template <typename Arg, typename Func>
    auto transformed(Arg&& arg, Func&& func) -> decltype(
        transformed(
            BinaryTransformWrapper<
                typename decay<Func>::type, 
                typename decay<Arg>::type
            >(std::forward<Func>(func), std::forward<Arg>(arg))
        )
    )
    {
        return transformed(
            BinaryTransformWrapper<
                typename decay<Func>::type, 
                typename decay<Arg>::type
            >(std::forward<Func>(func), std::forward<Arg>(arg))
        );
    }

}} // namespace boost::adaptors

步骤3:使用示例

现在你可以按照预期的方式调用,lambda不需要捕获任何变量,完全避免了引用捕获带来的问题:

#include <vector>

struct Foo { int x; int y; };

int main()
{
    std::vector<int> source = {1,2,3,4,5};
    Foo foo = {10, 20};

    // 直接传递Foo对象(会拷贝)
    auto tr1 = source | boost::adaptors::transformed(foo, [](int i, const Foo& f){
        return i + f.x;
    });

    // 如果想传递Foo的引用(避免拷贝),用std::ref包装
    auto tr2 = source | boost::adaptors::transformed(std::ref(foo), [](int i, const Foo& f){
        return i + f.x;
    });

    // 测试输出
    for (auto val : tr1)
        printf("%d ", val); // 输出:11 12 13 14 15
    return 0;
}

细节说明

  • 我们用std::forward和decay来处理参数的转发和类型退化,保证无论是左值、右值还是引用都能正确处理。
  • 包装器的operator()用尾置返回类型(auto -> decltype(...))来推导lambda的返回值,兼容VS2010的特性。
  • 如果要传递额外参数的引用,记得用std::ref或std::cref包装,否则会拷贝参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:44:16