c++: confusion about forwarding reference

寵の児 提交于 2019-12-23 06:31:07

问题


I read this (incredibly well written) article about Forwarding Reference in C++11 by Scott Meyers.

Now, focus on this part of the article:

template <class... Args>
void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction;
...                                // && ≡ universal references

So, in contrast with other cases, the ellipses doesn't make the && an rvalue reference, but it's still universal references.

From what I've understood, when we have universal references, we can call the function passing both rvalue and lvalues (wow, so cool!)

Now, I've implemented this function:

template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ...

So (using the same logic of the previous example), && means forwarding references.

But if I try to make this call:

typedef vector<double> vecD;
vecD vec;
mem.callFunction<vecD, vecD>(sortFunc, vec);

The compiler is going to complain with You cannot bind an lvalue to an rvalue reference

Why this happens?

THE WHOLE CODE:

#include <functional>
#include <vector>

using namespace std;
struct MultiMemoizator {
    template <typename ReturnType, typename... Args>
    ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) {

    }
};

typedef vector<double> vecD;

vecD sort_vec (vecD const& vec) {
    return vec;
}

int main()
{
    vecD vec;
    std::function<vecD(vecD)> sortFunc(sort_vec);
    MultiMemoizator mem;
    mem.callFunction<vecD, vecD>(sortFunc, vec);
}

回答1:


So first off, please use the "forwarding reference" instead of "universal reference". It better represents what it is and what its intended use is.

The first thing to be aware of is that not every && is a forwarding reference. It can also be an rvalue reference.

In simple terms T&& is a forwarding reference if and only if:

  • T is a simple (simple as shown next) type (so for instance vector<int>&& or vector<T>&& is not a forwarding reference).
  • and T is deduced.

In your example Args is not deduced. That is because you explicitly specify the function template argument Args when you call it:

mem.callFunction<vecD, vecD>(sortFunc, vec);
                       ^~~~

Let's work with something simpler to better understand:

Lets set up the scene:

struct X {};

template <class T>
auto foo(T&& p) {}

In the next 2 calls, we have forwarding references:

X x;
foo(x);

foo(X{});

In the first, T will be deduced as X& and by collapsing rules: X& && becomes X&, therefore we have an lvalue reference. As you would expect.

In the second, T will be deduced as X and by collapsing rules X && becomes X&&, therefore we have an rvalue reference.

But when you call it like this:

foo<X>(x);

T is no longer deduced. You basically say let T be X. So if T is X then T && is X&&, and you have the error: p whose type is now X&& cannot bind to an lvalue.


Holt also added:

Also note that because of the declaration of sortFunc, this would not work even if you did not specify the function template arguments explicitely.

I tend to agree with him, but I would need to investigate further to be sure of this.



来源:https://stackoverflow.com/questions/36842291/c-confusion-about-forwarding-reference

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!