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

Why C++ strings do not need std::forward to call the desired function?

我正在学习 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;
}

这里我尝试将一个左值和一个右值从test_forward_wrapper()转发到test_forward_inner()。 运行 这个程序给出了输出:

& example
& example

& hello
&& hello

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

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

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

区别在于

test_forward_wrapper("hello");

"hello" 这里不是 std::string。这是一个 const char *.

把这个改成

test_forward_wrapper(std::string("hello"));

结果将与自定义 class 相同。

请注意 "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,即右值,首选绑定到右值引用,这就是调用 test_forward_inner(string &&) 的原因。

将精确的 std::string 传递给 test_forward_wrapper() 将得到相同的结果。

test_forward_wrapper(std::string("hello"));