保存参考

发布于 2025-01-20 20:17:59 字数 2480 浏览 2 评论 0 原文

考虑以下简单的代码:

#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()非常紧密地使用使用的示例,但这并没有编译。我在做什么错?

Consider the following uncomplicated code:

#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's error on the last two lines, in particular, is

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,
      |                                            ^~~~~

I am sure this is a trivial matter, but I am anyway struggling to understand this. I think I have been following the available examples on std::thread::thread()'s intended use quite closely, but this does not compile. What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我乃一代侩神 2025-01-27 20:17:59

首先,让我澄清一下,因为我不确定它是否显而易见: std::ref 是它返回一个 std::reference_wrapper,因此可以将结果用作对象,但该对象可以隐式转换为 T&,因此可以在需要 T& 的地方进行替换。


lam(ref(x)); 失败,因为您在 lam 中使用了 auto。编译器不知道您希望 vl 成为 std::pair&,它会根据得到的内容进行推断。 std::ref 返回一个临时的 std::reference_wrapper>,它不能绑定到非 const参考。在 lambda 中使用显式类型并进行编译:

    auto lam = [&counter](std::pair<int, int>& vl) {
                vl = std::pair(counter++, -1);
            };
    lam(std::ref(x));

或者,您可以使用 get()static_cast 显式转换为 std::pair&

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

First, let me clarify, because I'm not sure if it's obvious: the trick behind std::ref is that it returns an object of type std::reference_wrapper<T>, so you can use the result as object, but the object is implicitly convertible to T&, so it can be substituted where T& is needed.


lam(ref(x)); fails because you use auto in lam. Compiler doesn't know that you want vl to be std::pair<int, int>&, it deduces from what it gets. std::ref returns a temporary of std::reference_wrapper<std::pair<int, int>>, which cannot be bound to non-const reference. Use explicit type in lambda and it compiles:

    auto lam = [&counter](std::pair<int, int>& vl) {
                vl = std::pair(counter++, -1);
            };
    lam(std::ref(x));

Alternatively, you can explicitly convert to std::pair<int, int>& using get() or static_cast

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

The second part with parallel_for has exactly the same issue, you pass rvalue of std::reference_wrapper to lam.

因为看清所以看轻 2025-01-27 20:17:59

关于

lam(ref(x));

x lvalue ,而 ref(x)是临时 reference> reference> reference_wrapper 。您无法通过 lam 通过 auto&amp; 中的LVALUE参考抓住临时参考。

对于那条线,您可以简单地使用

lam(x);

About

lam(ref(x));

x is an lvalue while the ref(x) is a temporary reference_wrapper. You can not grab a temporary with an lvalue reference in your lam through auto&.

for that line, you can simply use

lam(x);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文