1

I've got no idea why compiler gives me warnings about template instantiations.

Thats a piece of code which runs just fine and outputs lvalue/rvalue properly:

//template<typename T>
void overloaded(const /*T*/std::string& in)
{
    std::cout << "lvalue" << std::endl;
}

//template<typename T>
void overloaded(/*T*/std::string&& in)
{
    std::cout << "rvalue" << std::endl;
}

template<typename T>
void pass(T&& in)
{
    overloaded(std::forward<T>(in));
}

int main()
{
    std::string a;
    pass(a);
    pass(std::move(a));
    getchar();
}

But i need to use it with templated type. So modifying the "overloaded" functions to

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

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

Gives template instantiations warnings, (when to me its clear T should be std::string), and console outputs rvalue 2 times instead of lvalue first.

What am i doing wrong?

Pancake
  • 107
  • 9

1 Answers1

1

Templates such as T&& are special. They are called "forwarding references". They have special deduction rules for functions like:

template<typename T>
void overloaded(T&& in)

Assume for a moment that overloaded is not overloaded. If you pass an lvalue expression of type std::string to overloaded, T will deduce as std::string&. If you pass an rvalue expression of type std::string to overloaded, T will deduce to std::string. You can use this knowledge to do this:

template<typename T>
void overloaded(T&& in)
{
    if (std::is_lvalue_reference<T>::value)
        std::cout << "lvalue" << std::endl;
    else
        std::cout << "rvalue" << std::endl;
}

In general, it is an anti-pattern to overload T&& templates with anything else. These special templates come in handy when you want to catch everything.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577