C ++ 14 Lambda - 通过引用或值有条件地捕获

时间:2014-11-26 15:29:17

标签: c++ lambda c++14

是否可以根据编译时间信息有条件地选择lambda的捕获方法?例如......

auto monad = [](auto && captive) {
    return [(?)captive = std::forward<decltype(captive)>(captive)](auto && a) {
        return 1;
    };
};

如果decltype(captive)std::reference_wrapper,我希望通过引用进行捕获,并按值捕获所有其他内容。

2 个答案:

答案 0 :(得分:4)

Lambda捕获类型不能由依赖于模板的名称控制。

但是,您可以通过将内部lambda委托给重载函数来实现所需的效果:

template<class T>
auto make_monad(T&& arg) {
    return [captive = std::forward<T>(arg)](auto&& a) {
        std::cout << __PRETTY_FUNCTION__ << " " << a << '\n';
        return 1;
    };
}

template<class T>
auto make_monad(std::reference_wrapper<T> arg) {
    return [&captive = static_cast<T&>(arg)](auto&& a) {
        std::cout << __PRETTY_FUNCTION__ << " " << a << '\n';
        return 1;
    };
}

int main() {
    auto monad = [](auto&& captive) {
        return make_monad(std::forward<decltype(captive)>(captive));
    };

    int n = 1;
    monad(1)(1);
    monad(n)(2);
    monad(std::ref(n))(3);
}

输出:

make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int] 1
make_monad(T&&)::<lambda(auto:1&&)> [with auto:1 = int; T = int&] 2
make_monad(std::reference_wrapper<_Tp>)::<lambda(auto:2&&)> [with auto:2 = int; T = int] 3

  

我不想通过引用捕获reference_wrapper,我想通过引用捕获它所持有的引用。参考包装器最好像引用一样,但由于调用操作符(又名“。”操作符)不能重载,它在一天结束时会非常失败。

在这种情况下,您无需更改std::reference_wrapper<T>的捕获类型。相反,您可能希望像任何其他类型的参数一样按值捕获它,并在使用站点首先打开参数:

template<class T> T& unwrap(T& t) { return t; }
template<class T> T& unwrap(std::reference_wrapper<T> t) { return t; }

auto monad = [](auto && captive) {
    return [captive](auto && a) {            // <--- Capture by value.
        auto& captive_ref = unwrap(captive); // <--- Unwrap before usage.
        return 1;
    };
};

答案 1 :(得分:1)

它没有回答您的问题,但您的评论,如何使用operator .

您可以添加这两个重载:

template <typename T>
T& get_reference_object(T&& t) { return t; }

template <typename T>
T& get_reference_object(std::reference_wrapper<T> t) { return t.get(); }

然后你可以在你的lambda中使用get_reference_object(arg).foo

auto monad = [](auto && captive) {
    return [captive = captive](auto&& a) { return get_reference_object(captive).foo(a); };
};

Live example