c ++ 11 — поток C ++, принимающий ссылочный аргумент, не скомпилирован

#include<iostream>
#include<thread>
using namespace std;

void f1(double& ret) {
ret=5.;
}

int main() {
double ret=0.;
thread t1(f1, ret);
t1.join();
cout << "ret=" << ret << endl;
}

Приведенный выше код не может быть скомпилирован со следующим сообщение об ошибке:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
In file included from /usr/local/include/c++/5.3.0/thread:39:0,
from main.cpp:2:
/usr/local/include/c++/5.3.0/functional: In instantiation of 'struct std::_Bind_simple<void (*(double))(double&)>':
/usr/local/include/c++/5.3.0/thread:137:59:   required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(double&); _Args = {double&}]'
main.cpp:11:21:   required from here
/usr/local/include/c++/5.3.0/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/local/include/c++/5.3.0/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'
_M_invoke(_Index_tuple<_Indices...>)
^

Я понимаю, что я могу использовать std::ref() передать аргумент. Но если я передам по значению, почему это ошибка, так как thread следует просто скопировать аргумент значение и передать некоторый объект, хранящийся в потоке, чтобы связать его со ссылочным аргументом функции f1,

Я чувствую, что если я могу понять, что это result_of делает и почему он дает ошибку, я могу лучше понять причину. Так может ли кто-нибудь провести меня через сообщение об ошибке? Особенно значения std::_Bind_simple<void (*(double))(double&)> а также std::result_of<void (*(double))(double&)>,

РЕДАКТИРОВАТЬЯ знаю, если я передам значение, поток будет работать только с копией и не будет иметь никакого эффекта после того, как поток вернется. Это не моя забота. Я хочу знать, почему он выдает ошибку сейчас, но он не давал ошибки другим постам на SO, например:Разница между указателем и ссылкой в ​​качестве параметра потока

8

Решение

Я знаю, если я передам значение, поток будет работать только с копией и не будет иметь никакого эффекта после того, как поток вернется.

Нет, это не правильно. Код не должен молча делать копию и работать с ней, согласно стандарту, он даже не должен компилироваться.

Стандарт требует, чтобы аргументы вызываемой функции были скопированы (в хранилище, управляемое средой выполнения C ++), а затем копии пересылаются как значения. Так в вашем примере f1 получает значение типа double и параметр типа double& не может связываться с этим значением.

Причина, по которой стандарт требует этого, заключается в том, что нет тихого копирования и потери данных: если функция требует изменяемой ссылки, она не скомпилируется, если вы не передадите ссылку явно, используя reference_wrapper,

Ошибка компилятора, которую вы получаете result_of потому что так я сделал GCC std::thread проверьте, может ли функция вызываться с предоставленными аргументами. я использую result_of<decltype(&f1)(double)> проверить, если указатель на функцию &f1 (который имеет тип void(*)(double&)) можно вызывать с помощью значения типа r double, Его нельзя вызывать с аргументом этого типа, поэтому вложенный тип result_of<decltype(&f1)(double)>::type не определено, поэтому компилятор говорит:

error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'

Ошибка немного сбивает с толку, потому что правила декларатора C ++ означают, что decltype(&f1)(double) отображается как void(*(double))(double&),

Это не моя забота. Я хочу знать, почему он дает ошибку сейчас, но он не дает ошибки другим постам на SO

В этих сообщениях использовался старый пре-C ++ 11 или несовместимый компилятор, который не отвечал требованиям стандарта C ++ 11 и неправильно компилировал код.

12

Другие решения

Ответ Джонатана окончательный. Время, потраченное на изучение, будет хорошо проведено.

Тем временем, изменение кода, таким образом, будет делать то, что вы хотите, а именно — отправлять ссылку в функцию потока:

thread t1(f1, std::ref(ret));
1

По вопросам рекламы [email protected]