为什么C++字符串不需要std :: forward来调用所需的函数?

PJ.*_*des 5 c++ templates rvalue-reference perfect-forwarding c++11

我正在学习std::forward.我写了一个简短的程序来测试如果我们std::forward在将参数转发给另一个函数调用之前没有调用会发生什么:

#include <iostream>
#include <typeinfo>
#include <string>
using namespace std;

class Example {
};

ostream &operator << (ostream &os, const Example &e) { os << "yes!"; return os; }

void test_forward_inner(const Example &e) { cout << "& " << e << endl; }
void test_forward_inner(Example &&e) { cout << "&& " << e << endl; }

void test_forward_inner(const string &e) { cout << "& " << e << endl; }
void test_forward_inner(string &&e) { cout << "&& " << e << endl; }

template <typename T>
void test_forward_wrapper(T &&arg) {
    test_forward_inner(arg);
}

int main()
{
    Example e;
    test_forward_wrapper(e);
    test_forward_wrapper(Example());

    cout << endl;

    string s("hello");
    test_forward_wrapper(s);
    test_forward_wrapper("hello");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这里,我尝试将一个左值和一个右值转发test_forward_wrapper()test_forward_inner().运行此程序给出输出:

& example
& example

& hello
&& hello
Run Code Online (Sandbox Code Playgroud)

对于std::strings,调用了所需的内部函数,但对于我自己的类,只调用了左值函数.只有在我std::forward将参数传递给内部函数之前调用才能调用rvalue版本.

这有什么不同?据我所知,根据参考折叠规则,当调用包装器时Example(),rvalue T将被推导为Example并且arg具有类型,Example &&因此应该调用内部函数的rvalue版本.

而且,对于像std::string这里的情况这样的其他情况,调用了内部函数的正确版本,那么我们可以删除std::forward这里吗?如果没有,会发生什么(可能是坏事)?

son*_*yao 7

请注意,"hello"不是std::string,它是一个const char[6].并且test_forward_wrapper()是一个函数模板,模板参数T将被推导出来char const (&)[6].

在里面test_forward_wrapper(),test_forward_inner()被称为const char[6],需要首先转换为std::string.这是一个临时的std::string,即一个rvalue,首选绑定到右值引用,这就是为什么test_forward_inner(string &&)被调用.

传递精确std::stringtest_forward_wrapper()将获得相同的结果.

test_forward_wrapper(std::string("hello"));
Run Code Online (Sandbox Code Playgroud)