【问题标题】:Why C++ strings do not need std::forward to call the desired function?为什么 C++ 字符串不需要 std::forward 来调用所需的函数?
【发布时间】:2016-09-02 03:08:50
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    注意"hello" 不是std::string,它是const char[6]。而test_forward_wrapper()是一个函数模板,模板参数T会被推导出为char const (&amp;)[6]

    test_forward_wrapper()内部,test_forward_inner()是用const char[6]调用的,首先需要转换成std::string。这是一个临时的std::string,即右值,首选绑定到右值引用,这就是调用test_forward_inner(string &amp;&amp;) 的原因。

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

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

    【讨论】:

      【解决方案2】:

      区别在于

      test_forward_wrapper("hello");
      

      这里的“你好”不是std::string。这是const char *

      把它改成一个

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

      结果将与自定义类的结果相同。

      【讨论】:

      • 重要的部分是包装器是模板化的(因此在该调用中不会发生强制),而内部函数不是,只接受std::string,这意味着转换为string 然后发生(提供对内部函数的 r 值引用),不涉及转发。
      • "hello" 不是const char *,而是可以衰减为const char *const char[6]。 .
      • ^(在这种情况下不会衰减)
      猜你喜欢
      • 2017-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      相关资源
      最近更新 更多