EnDelt64
EnDelt64

Reputation: 1360

Role of std::forward

Following is the code brought from this question.

// [I]
void overloaded_function(const std::string& param) {
    std::cout << "const std::string& version: " << param << '\n';
}

// [II]
void overloaded_function(std::string&& param) {
    std::cout << "std::string&& version: " << param << '\n';
}

template <typename T>
void pass_through_f(T&& param) {
    overloaded_function(std::forward<T>(param));
}

template <typename T>
void pass_through(T&& param) {
    overloaded_function(param);
}

int main() {
    std::string str = "Hello World";

    pass_through_f(str);            // (1)
    pass_through_f(std::move(str)); // (2)

    std::cout << "----------\n";

    pass_through(str);              // (3)
    pass_through(std::move(str));   // (4)

    return 0;
}
const std::string& version: Hello World
std::string&& version: Hello World
----------
const std::string& version: Hello World
const std::string& version: Hello World

When I use pass_through_f(), the result between (1) and (2) is different but they are same when pass_though() is called.

My question is, how is the result of (4) same with (3)? Here's type inferencing process that I thought:

  1. In (4), return value of some function is r-value, so T of pass_through() is inferred as a type same with passed argument. Thus T is std::string&&.

  2. std::string&& is r-value reference, and r-value reference is r-value so it calls overloaded_function() [II]. Thus its result is same with when std::forward is used.

But result is different with my thought. I think I'm misunderstanding something about the way std::forward works.

Upvotes: 1

Views: 78

Answers (1)

NathanOliver
NathanOliver

Reputation: 180490

The problem is that in

template <typename T>
void pass_through(T&& param) {
    overloaded_function(param);
}

param is a named variable. Since it has a name, it is an lvalue, even though it is a reference to an rvalue. Since it is an lvalue, you call the lvalue function.

You need std::forward to "re-cast" it back into a rvalue if it came in as an rvalue.


Also note that T is not string&&. Since you passed a string&&, T&& deduces T to string and the && is kept to make it an rvalue reference.

Upvotes: 2

Related Questions