ошибка C2783: ‘_Ty & amp; std :: forward (remove_reference & lt; _Ty & gt; :: type & amp; & amp;) throw ()’: не удалось вывести аргумент шаблона для ‘_Ty’

У меня есть шаблонная реализация параллельной очереди, которая имеет функцию push, которая выглядит следующим образом:

template <typename T>
class concurrent_queue
{
public:

// other code...

void push(const T& item)
{
std::unique_lock<std::mutex> mlock(mutex);
queue.push_back(std::forward(item));
mlock.unlock();
notEmpty.notify_one();
}

private:

std::deque<T>               queue;
std::mutex                  mutex;
// other stuff...
};

Позже я создаю его и использую так:

concurrent_queue<c2Type> m_queue;  // c2 type is some struct declared previously

и затем я пытаюсь поместить элементы в очередь и получаю вышеупомянутую ошибку компилятора:

c2Type c2message;

// fill in the message struct...
m_queue.push(c2message);

Я успешно использовал очередь раньше как часть реализации пула потоков, где она хранилась std::function объекты. Я не понимаю, почему он не может вывести тип в этом случае. Какие-нибудь мысли?

3

Решение

Категории значений, такие как «lvalue» и «rvalue», являются свойствами выражений. Выражения, которые называют переменные, всегда являются lvalue-выражениями, даже если они называют переменную, которая имеет тип Rvalue ссылка на some_type.

Мы используем lvalue-reference и rvalue-ссылки, чтобы связать различные категории выражений: в соответствии с соглашением мы рассматриваем lvalue-ссылки как быть привязанным к ценностям, и rvalue-ссылки как быть привязанным к ценностям.

std::forward предназначен для восстановления категории значения того, к чему мы относимся. Например:

int   i = 42;
int&  l = i;
int&& r = 21;

l // this expression is an lvalue-expression
r // this expression is an lvalue-expression, too (!)

std::forward<int& >(l) // this function-call expression is an lvalue-expression
std::forward<int&&>(r) // this function-call expression is an rvalue-expression

std::forwardбудучи «обычной функцией», не может восстановить категорию значений просто с помощью аргумента. Оба аргумента являются lvalue-выражениями. Вы должны указать, какую категорию значений вы хотите восстановить, вручную указав аргумент шаблона.

Это имеет смысл, только если у нас есть ссылка, в которой мы априори не знаем, является ли это rvalue-ссылкой или lvalue-ссылкой. Это имеет место при написании функции, которая использует идеальная пересылка с пересылка ссылок.

Кстати, мы хотим восстановить категорию значений, чтобы позволить другой функции перейти от полученного нами аргумента. Если мы получим аргумент rvalue, мы хотим передать значение rvalue, чтобы позволить вызываемой функции перемещаться.


Для функции, подобной той, что в OP:

void push(const T& item)

Мы знаем это item имеет тип lvalue ссылка на const T. Поэтому нам не нужно std::forward:

void push(const T& item) {
// ...
queue.push_back(item); // pass the lvalue argument as an lvalue
// ...
}

Если мы добавим еще одну перегрузку:

void push(T&& item)

нам все еще не нужно std::forward, так как тип этого параметра item всегда rvalue-ссылка на T (при условии, T не ссылочный тип):

void push(T&& item) {
// ...
queue.push_back(std::move(item)); // pass the rvalue argument as an rvalue
// ...
}

Только если у нас есть что-то вроде

template<typename U>
void push(forwarding_reference<U> item)

где forwarding_reference<U> может быть либо именующая ссылка или Rvalue ссылка, тогда нам нужно std::forward:

template<typename U>
void push(forwarding_reference<U> item) // not C++, read on
{
// ...
queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
// and rvalue arguments as rvalues
// ...
}

Из-за деталей реализации, мы должны написать выше как:

template<typename U>
void push(U&& item) {
// ...
queue.push_back(std::forward<U>(item)); // pass lvalue arguments as lvalues
// and rvalue arguments as rvalues
// ...
}

Обратите внимание, что выше U&& item является не rvalue-ссылка, но ссылка для пересылки. Чтобы получить ссылку на пересылку, вам нужно иметь шаблон функции с некоторым параметром типа шаблона X и параметр функции вида X&& x,

7

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


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