简体   繁体   中英

error C2783: '_Ty &&std::forward(remove_reference<_Ty>::type &&) throw()' : could not deduce template argument for '_Ty'

I have a templated implementation of a concurrent queue that has a push function that looks like:

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...
};

Later on, I instantiate it and use it like so:

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

and then I try to push items on the queue and I get the afore mentioned compiler error:

c2Type c2message;

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

I've sucessfully used the queue before as part of a thread pool implementation where it stored std::function objects. I don't understand why it can't deduce the type in this case. Any thoughts?

Value categories like "lvalue" and "rvalue" are properties of expressions. Expressions that name variables are always lvalue-expressions, even if they name a variable that has the type rvalue reference to some_type .

We use lvalue-reference and rvalue-references to bind different categories of expressions: Per convention, we treat lvalue-references as being bound to lvalues , and rvalue-references as being bound to rvalues .

std::forward is intended to restore the value category of what we assume a reference refers to. For example:

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 , being "an ordinary function", cannot restore the value category merely by using the argument. Both arguments are lvalue-expressions. You have to specify which value category you want to restore by manually supplying the template-argument.

This makes only sense if we have a reference where we don't know a priori whether it's an rvalue-reference or an lvalue-reference. That is the case when writing a function that uses perfect forwarding with forwarding references .

By the way, we want to restore the value category to allow another function to move from the argument we have received. If we receive an rvalue argument, we want to pass on an rvalue, to allow the called function to move.


For a function like the one in the OP:

void push(const T& item)

We know that item has the type lvalue reference to const T . Therefore, we don't need std::forward :

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

If we add another overload:

void push(T&& item)

we still don't need std::forward , since the type of that parameter item is always rvalue-reference to T (assuming T is not a reference type) :

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

Only if we have something like

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

where forwarding_reference<U> can be either an lvalue-reference or an rvalue-reference , then we need 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
    // ...
}

Due to implementation details, we must write the above as:

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

Note that the above U&& item is not an rvalue-reference, but a forwarding reference. To get a forwarding reference, you need to have a function template with some template type parameter X and a function parameter of the form X&& x .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM