如何在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
相关产品推荐
相关产品推荐

