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

标签 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,我想通过引用捕获,而其他一切都通过值捕获。

最佳答案

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

但是,您可以通过将创建内部 lambda 委托(delegate)给重载函数来达到预期的效果:

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

I don't want to capture reference_wrapper by reference, I want to capture the reference it holds by reference. 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.

在这种情况下,您不需要更改 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;
    };
};

关于C++14 Lambda - 通过引用或值有条件地捕获,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27152948/

相关文章:

c# - 了解 ClientContext.Load 的参数

c# - 使用 lambda 表达式注册类型

c++ - 如何在 C++ 中使用可变参数泛型 lambda 计算总和?

C++ 从参数参数包创建 vector 或列表

c++ - Infix To Postfix 的输出中没有运算符和括号

c++ - 如果没有堆内存,如何释放 std::vector

c++11 lambda高阶函数包装器递归错误

c++ - MinGW g++ 4.8.1-4 无法识别 -std=c++14

c++ - 使用 libcql 的 Cassandra 表的列名

c++ - 传入并存储指向对象的函数指针