Переслать вариационный аргумент в поток с лямбдой

У меня проблемы с поиском, как использовать std::thread() с лямбдами. А именно, при наличии аргумента с переменным значением лямбда получает аргументы путем пересылки. В качестве примера:

template<typename... T> 
auto foo(T&&... t){
    [](T&&... t){}(std::forward<T>(t)...); // (1)

    return std::thread( // (2) 
        [](T&&... t){},
        std::forward<T>(t)...
    );
}

auto bar(){
    int n=1;
    foo(1); (A)
    foo(n); (B)
}

A.1: компилирует

A.2: компилирует

B.1: компилирует

B.2: не компилируется

Я не понимаю

  • Почему std::thread() (2) версия с использованием (B) не компилируется и (A.2) делает?
  • Почему существуют различия между (B.1) и (B.2)

2 ответа

Решение

Попробуй с

template<typename... T> 
auto foo(T&&... t){
    [](T&&... u){ }(std::forward<T>(t)...); // (1)

    return std::thread( // (2) 
        [](auto &&... u){ },
        std::forward<T>(t)...
    );
}

Я имею в виду: в лямбде вы переходите к std::thread(), auto && ... вместо T && ..., Или, может быть, T const & ...,

Я не являюсь языковым слоем, и, возможно, кто-то может исправить меня, но мне кажется, что существует конфликт между универсальными ссылками и ссылками на r-значения. И тот факт, что std::thread() передать копии следующих аргументов первому.

Когда ты пишешь

template<typename... T> 
auto foo(T&&... t)

&& универсальные ссылки и T... становиться intкогда вы звоните foo(1), а также int &когда вы звоните foo(n),

Внутри функции вы получаете

[](int){ }(std::forward<int>(t)); // (1)

return std::thread( // (2) 
    [](int){ },
    std::forward<int>(t)...
);

в случае f(0),

И это работает, потому что оба лямбда ждут int по копии, и это всегда работает.

Но когда вы звоните f(n)внутри foo() ты получаешь

[](int &){ }(std::forward<int>(t)); // (1)

return std::thread( // (2) 
    [](int &){ },
    std::forward<int>(t)...
);

и это работает для первого звонка, потому что лямбда подождите int переменная левой ссылки (int &) и получить int переменная левой ссылки, но не работает для второго вызова, потому что std::thread передать копию std::forward<int>(t) (так что правильная ссылка, int &&) к лямбде, которая ждет левой ссылки.

std::thread не может просто пересылать свои аргументы в лямбду по ссылке, потому что это будет означать, что два потока потенциально имеют одновременный доступ к аргументам без синхронизации. Так что вместо этого std::thread создает временные копии аргументов и передает их в лямбду. Потому что они временные, они ценности. Это работает в A.2, потому что лямбда-параметр является rvalue ссылкой (потому что T является int, так T&& является int&&). Это не работает в B.2, потому что параметр лямбды является ссылкой lvalue (потому что T является int&, так T&& является int&). Как говорит max66, вы, вероятно, хотите использовать auto&&... в вашей лямбде, чтобы она могла принять все, что ей передано.

Другие вопросы по тегам