保存参考
Saving references
考虑以下简单代码:
#include <thread>
#include <utility>
#include <vector>
#include <atomic>
#include <queue>
#include <iostream>
#include <functional>
using namespace std;
template<class It, class Fun>
void parallel_for(size_t num_threads, It first, It end, const Fun& fun) {
std::queue<std::thread> ts;
for (It it = first; it != end; ++it) {
if (std::distance(first, it) % num_threads == 0) {
fun(*it);
} else {
if (ts.size() == num_threads-1) {
ts.front().join();
ts.pop();
}
ts.push(std::thread(fun, std::ref(*it)));
}
}
while (not ts.empty()) {
ts.front().join();
ts.pop();
}
}
int main() {
std::atomic_int counter = 1;
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
// The following usage of std::ref works okay:
pair<int, int> x;
auto blam = bind(lam, ref(x));
blam();
// Nevertheless, the next line fails:
// lam(ref(x));
// As well as the next two ones:
// vector<pair<int, int>> v = {{4, 2}};
// parallel_for(thread::hardware_concurrency(), begin(v), end(v), lam);
return 0;
}
GCC 在最后两行的错误,特别是
In file included from ./src/csc_cpp/passing_lambdas.cpp:1:
/usr/include/c++/10/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(auto:1&)>&; _Args = {std::reference_wrapper<std::pair<int, int> >}; <template-parameter-1-3> = void]’:
./src/csc_cpp/passing_lambdas.cpp:22:26: required from ‘void parallel_for(size_t, It, It, const Fun&) [with It = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; Fun = main()::<lambda(auto:1&)>; size_t = long unsigned int]’
./src/csc_cpp/passing_lambdas.cpp:47:71: required from here
/usr/include/c++/10/thread:136:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
136 | typename decay<_Args>::type...>::value,
| ^~~~~
我确信这是一件小事,但无论如何我都在努力理解这一点。我想我一直在非常密切地关注 std::thread::thread()
的预期用途的可用示例,但这不会编译。我做错了什么?
关于
lam(ref(x));
x
是一个 lvalue
而 ref(x)
是一个临时的 reference_wrapper
。您不能在 lam
到 auto&
.
中获取带有左值引用的临时文件
对于该行,您可以简单地使用
lam(x);
首先,让我澄清一下,因为我不确定它是否显而易见:std::ref
is that it returns an object of type std::reference_wrapper<T>
背后的技巧,因此您可以将结果用作对象,但该对象可隐式转换为 T&
, 所以可以在需要 T&
的地方替换.
lam(ref(x));
失败,因为您在 lam
中使用了 auto
。编译器不知道您希望 vl
成为 std::pair<int, int>&
,它会根据得到的内容进行推断。 std::ref
returns std::reference_wrapper<std::pair<int, int>>
的临时值,不能绑定到非 const
引用。在 lambda 中使用显式类型并编译:
auto lam = [&counter](std::pair<int, int>& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x));
或者,您可以使用 get()
或 static_cast
显式转换为 std::pair<int, int>&
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x).get());
lam(static_cast<std::pair<int, int>&>(std::ref(x)));
parallel_for
的第二部分具有完全相同的问题,您将 std::reference_wrapper
的右值传递给 lam
。
考虑以下简单代码:
#include <thread>
#include <utility>
#include <vector>
#include <atomic>
#include <queue>
#include <iostream>
#include <functional>
using namespace std;
template<class It, class Fun>
void parallel_for(size_t num_threads, It first, It end, const Fun& fun) {
std::queue<std::thread> ts;
for (It it = first; it != end; ++it) {
if (std::distance(first, it) % num_threads == 0) {
fun(*it);
} else {
if (ts.size() == num_threads-1) {
ts.front().join();
ts.pop();
}
ts.push(std::thread(fun, std::ref(*it)));
}
}
while (not ts.empty()) {
ts.front().join();
ts.pop();
}
}
int main() {
std::atomic_int counter = 1;
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
// The following usage of std::ref works okay:
pair<int, int> x;
auto blam = bind(lam, ref(x));
blam();
// Nevertheless, the next line fails:
// lam(ref(x));
// As well as the next two ones:
// vector<pair<int, int>> v = {{4, 2}};
// parallel_for(thread::hardware_concurrency(), begin(v), end(v), lam);
return 0;
}
GCC 在最后两行的错误,特别是
In file included from ./src/csc_cpp/passing_lambdas.cpp:1:
/usr/include/c++/10/thread: In instantiation of ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = const main()::<lambda(auto:1&)>&; _Args = {std::reference_wrapper<std::pair<int, int> >}; <template-parameter-1-3> = void]’:
./src/csc_cpp/passing_lambdas.cpp:22:26: required from ‘void parallel_for(size_t, It, It, const Fun&) [with It = __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int> > >; Fun = main()::<lambda(auto:1&)>; size_t = long unsigned int]’
./src/csc_cpp/passing_lambdas.cpp:47:71: required from here
/usr/include/c++/10/thread:136:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
136 | typename decay<_Args>::type...>::value,
| ^~~~~
我确信这是一件小事,但无论如何我都在努力理解这一点。我想我一直在非常密切地关注 std::thread::thread()
的预期用途的可用示例,但这不会编译。我做错了什么?
关于
lam(ref(x));
x
是一个 lvalue
而 ref(x)
是一个临时的 reference_wrapper
。您不能在 lam
到 auto&
.
对于该行,您可以简单地使用
lam(x);
首先,让我澄清一下,因为我不确定它是否显而易见:std::ref
is that it returns an object of type std::reference_wrapper<T>
背后的技巧,因此您可以将结果用作对象,但该对象可隐式转换为 T&
, 所以可以在需要 T&
的地方替换.
lam(ref(x));
失败,因为您在 lam
中使用了 auto
。编译器不知道您希望 vl
成为 std::pair<int, int>&
,它会根据得到的内容进行推断。 std::ref
returns std::reference_wrapper<std::pair<int, int>>
的临时值,不能绑定到非 const
引用。在 lambda 中使用显式类型并编译:
auto lam = [&counter](std::pair<int, int>& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x));
或者,您可以使用 get()
或 static_cast
std::pair<int, int>&
auto lam = [&counter](auto& vl) {
vl = std::pair(counter++, -1);
};
lam(std::ref(x).get());
lam(static_cast<std::pair<int, int>&>(std::ref(x)));
parallel_for
的第二部分具有完全相同的问题,您将 std::reference_wrapper
的右值传递给 lam
。