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

时间:2016-09-02 03:08:51

标签: c++ templates c++11 rvalue-reference perfect-forwarding

我正在学习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::string s,调用了所需的内部函数,但对于我自己的类,只调用了左值函数。只有在将参数传递给内部函数之前调用std::forward,才能调用rvalue版本。

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

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

2 个答案:

答案 0 :(得分: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::string传递给test_forward_wrapper()会得到相同的结果。

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

答案 1 :(得分:4)

区别在于

test_forward_wrapper("hello");

&#34;你好&#34;这里不是std::string。它是const char *

将其更改为

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

结果将与自定义类相同。