简体   繁体   English

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

[英]C++14 Lambda - Conditionally Capture by Reference or Value

Is it possible to conditionally choose the capture method of a lambda based on compile time information? 是否可以根据编译时间信息有条件地选择lambda的捕获方法? For example... 例如...

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

I want capture by reference if decltype(captive) is a std::reference_wrapper , and everything else captured by value. 如果decltype(captive)std::reference_wrapper ,我希望通过引用捕获,以及通过value捕获的所有其他内容。

Lambda capture type cannot be controlled by template-dependent names. Lambda捕获类型不能由依赖于模板的名称控制。

However, you could achieve the desired effect by delegating creating the inner lambda to an overloaded function: 但是,您可以通过将内部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);
}

Outputs: 输出:

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

I don't want to capture reference_wrapper by reference, I want to capture the reference it holds by reference. 我不想通过引用捕获reference_wrapper,我想捕获它通过引用保存的引用。 Reference wrapper does it's best to be a like a reference, but since the call operator (aka, "." operator) cannot be overloaded, it fails pretty miserably at the end of the day. 参考包装器最好是像引用一样,但由于调用操作符(又名“。”操作符)不能重载,它在一天结束时会非常失败。

In this case you do not need to change the capture type for std::reference_wrapper<T> . 在这种情况下,您无需更改std::reference_wrapper<T>的捕获类型。 Instead, you may like to capture it by value like any other type of argument and at the usage site unwrap the argument first: 相反,您可能希望像任何其他类型的参数一样通过值捕获它,并在使用站点首先解开参数:

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;
    };
};

It doesn't answer your question but your comment, How to use operator . 它不回答您的问题,但您的评论,如何使用operator . :

You may add those two overloads: 您可以添加这两个重载:

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(); }

and then you may use get_reference_object(arg).foo inside your lambda: 然后你可以在你的lambda中使用get_reference_object(arg).foo

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

Live example . 实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM