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

如何在C++泛型lambda的auto&&参数上实现完美转发?

如下泛型lambda可用于保护线程间共享资源的任意操作:

auto mutexed = [mtx(std::mutex{})](auto &&fn, auto &&...args) mutable {
    std::unique_lock lo(mtx);
    return fn(args...);
    //return std::forward<decltype(fn)>(fn)(std::forward<decltype(args)>(args)...);
};

decltype(fn) 不满足完美转发的要求:它对值类型和右值引用有效,但无法适配左值引用;而使用decltype((fn))可适配左值引用,却又无法兼容右值引用。

因此我们需要解决的问题是:如何实现能够同时完美转发左值引用和右值引用的泛型lambda?

避免线程操作破坏标准输出的示例代码如下:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
using namespace std::chrono_literals;
using std::cout, std::clog, std::cerr, std::endl;

int main() {
    cout << "Hello, World!" << endl;

    auto mutexed = [mtx(std::mutex{})](auto &&fn, auto &&...args) mutable {
        std::unique_lock lo(mtx);
        //return fn(args...);
        return std::forward<decltype(fn)>(fn)(std::forward<decltype(args)>(args)...);
    };
    
    int counter = 0;
    auto t1 = std::thread( [&](){ 
        while(1){ 
            std::this_thread::sleep_for(10ms);
            // mutexed( [](int&&cnt){ cout << cnt++ << endl; }, std::move(counter) ); //此处会失败
            mutexed( [](int&cnt){ cout << cnt++ << endl; }, counter );  //左值引用可正常工作
        }
    });

    auto t2 = std::thread([&]{ 
        while(1){
        std::this_thread::sleep_for(10ms);
        mutexed( []{ cout << "done long_operation_2" << endl;});}
    });

    t1.join();
    t2.join();
}

兼容C++11、14、17、20、23版本的可行解决方案

int main() {
    auto lambda20 = []<class F, class...Ts>(F &&fn, Ts &&...args) {
        return std::forward<F>(fn)(std::forward<Ts>(args)...);
    };
    auto lambda14 = [](auto &&fn, auto &&...args) {
        return std::forward<
                std::conditional_t<
                        std::is_rvalue_reference_v<decltype(fn)>,
                        typename std::remove_reference_t<decltype(fn)>,
                        decltype(fn)>
        >(fn)(
                std::forward<
                        std::conditional_t<std::is_rvalue_reference<decltype(args)>::value,
                                typename std::remove_reference<decltype(args)>::type,
                                decltype(args)
                        >>(args)...);
    };
    int inter = 20;
    lambda20([](int x) { cout << "asdf20   x" << endl; }, inter);
    lambda20([](int &x) { cout << "asdf20  &x" << endl; }, inter);
    lambda20([](int &&x) { cout << "asdf20 &&x" << endl; }, std::move(inter));
    lambda14([](int x) { cout << "asdf14   x" << endl; }, inter);
    lambda14([](int &x) { cout << "asdf14  &x" << endl; }, inter);
    lambda14([](int &&x) { cout << "asdf14 &&x" << endl; }, std::move(inter));

    return 0;
}

C++20之前版本的解决方案出自Scott Meyers早年发布的技术文章。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:24:03