0

May be duplicated to this.

I read Effective Modern C++. Under Item 1, I found a case for universal reference:enter image description here

For the last example f(27); I did a test under VS2013.

void process(int& x)
{
    std::cout << "int&" << std::endl;
}
void process(int&& x)
{
    std::cout << "int&&" << std::endl;
}
template<typename T>
void f(T&& param)
{
    std::cout << "------------------------------------------------" << std::endl;
    if (std::is_lvalue_reference<T>::value)
    {
        std::cout << "T is lvalue reference" << std::endl;
    }
    else if (std::is_rvalue_reference<T>::value)
    {
        std::cout << "T is rvalue reference" << std::endl;
    }
    else
    {
        std::cout << "T is NOT lvalue reference" << std::endl;
    }
    std::cout << "param is: " << typeid(param).name() << std::endl;

    process(std::forward<T>(param));
    process(param);
}
int getINT()
{
    int x = 10;
    return x;
}
int _tmain(int argc, _TCHAR* argv[])
{   
    f(10);
    f(getINT());

    return 0;

}

Here is the output:

------------------------------------------------
T is NOT lvalue reference
param is: int
int&&
int&
------------------------------------------------
T is NOT lvalue reference
param is: int
int&&
int&

I found that within the template function, without std::forward<T>(param), process(int& x) will be called but according to the book, the type for param should be rvalue reference, so process(int&& x) should be called. But this is not the case. Is it I misunderstand something?

Here is the forwarding reference I found from other thread: enter image description here

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
sflee
  • 1,659
  • 5
  • 32
  • 63

1 Answers1

1

You're confusing types with value categories. As a named parameter, param is an lvalue, then for process(param); process(int& x) will be called.

That's why we should use std::forward with forwarding reference; std::forward<T>(param) converts param to rvalue for this case, then process(int&& x) will be called (as expected).

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • So you mean that if I have `int&& x = 10;`, then what type is `x`? It is not rvalue reference? – sflee Jul 20 '17 at 02:10
  • 1
    @sflee Its type is `int&&`, but it's an lvalue. Lvalue can't be bound to rvalue-reference, then `process(int&& x)` won't be selected when being called. – songyuanyao Jul 20 '17 at 02:13
  • @songyuanyao its type is `int` and its value category is "lvalue" – M.M Jul 20 '17 at 02:24
  • @M.M For `int&& x` shouldn't the type be `int&&` (i.e. rvalue-reference to `int`) ? – songyuanyao Jul 20 '17 at 02:26
  • 1
    The expression `x` has type `int` . Expressions never have reference type. If talking about the entity `x` I tend to say "the declared type of `x` is `int&&`" ; if you don't make this distinction then it is ambiguous to talk about "the type of `x`" – M.M Jul 20 '17 at 02:36
  • 1
    @M.M I got what you mean. Here I think saying "the declared type of `x` is `int&&` but its value category is lvalue" should be most clear to OP. – songyuanyao Jul 20 '17 at 02:40
  • 1
    @songyuanyao the entity `x` doesn't have a value category though - only expressions have value categories. – M.M Jul 20 '17 at 02:47
  • @M.M Okay, then it would be "even the declared type of `x` is `int&&` but when used as expression its value category is lvalue". – songyuanyao Jul 20 '17 at 02:49
  • Thank you very much songyuanyao and M.M – sflee Jul 20 '17 at 04:56