Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload between rvalue reference and const lvalue reference in template

I want to overload two functions based on whether the argument is a temporary object, so I write code like this:

#include <iostream>

void f(int &&)
{
  std::cout << "&&" << std::endl;
}

void f(const int&)
{
  std::cout << "const &" << std::endl;
}

int main()
{
  int i;
  f(i);
  f(i + 1);
}

And it corrently output:

const &
&&

However, when I change the code to use template like this:

#include <iostream>

template <typename T>
void f(T &&)
{
  std::cout << "&&" << std::endl;
}

template <typename T>
void f(const T&)
{
  std::cout << "const &" << std::endl;
}

int main()
{
  int i;
  f(i);
  f(i + 1);
}

The output becomes:

&&
&&

What's the problem? How can I optimize for moveable temporary object when using template?

edit:

Actually, this is a test code when I read C++ Primer. It says:

template <typename T> void f(T&&);       // binds to nonconst rvalues
template <typename T> void f(const T&);  // lvalues and const rvalues

After my experiment, it seems the book makes a mistake here.

like image 208
delphifirst Avatar asked Jan 08 '15 08:01

delphifirst


1 Answers

template <typename T>
void f(T &&)
{
  std::cout << "&&" << std::endl;
}

Uses universal forwarding reference and allows any types with reference collapsing.

You have to use T with a no deducing context as wrapping your code into a struct:

template <typename T>
struct helper
{

    void f(T &&)
    {
      std::cout << "&&" << std::endl;
    }

    void f(const T&)
    {
      std::cout << "const &" << std::endl;
    }

};

template <typename T>
void f(T &&t)
{
     helper<typename std::decay<T>::type>().f(std::forward<T>(t));
}

Live example

like image 75
Jarod42 Avatar answered Nov 14 '22 23:11

Jarod42