2016-09-02 1 views
5

Я учусь std::forward. Я написал небольшую программу, чтобы проверить, что произойдет, если мы не будем называть std::forward перед передачей аргументов на другой вызов функции:Почему строки C++ не нуждаются в 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; 
} 

Здесь я попытался направить Левое и в RValue от test_forward_wrapper() до test_forward_inner(). Выполнение этой программы дает результат:

& example 
& example 

& hello 
&& hello 

Для std::string с, желаемой внутренней функцией называлось, но для моего собственного класса была названа только версия именующей. Только если я вызываю std::forward перед передачей аргументов внутренней функции, может вызываться rvalue-версия.

В чем здесь разница? Как я знаю, в соответствии с правилами сбрасывания ссылок, когда обертка была вызвана с Example(), значение r12, T будет выведено как Example, а arg будет иметь тип Example &&, таким образом, следует вызывать версию внутренней функции rvalue.

И для других ситуаций, таких как случай std::string, здесь была выбрана правильная версия внутренней функции, тогда мы можем удалить здесь std::forward? Если нет, что (может быть, что-то плохое) произойдет?

ответ

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, предпочтительнее привязываться к ссылке rvalue, поэтому вызывается test_forward_inner(string &&).

Пройдя точный std::string до test_forward_wrapper(), вы получите тот же результат.

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

Разница заключается в том, что в

test_forward_wrapper("hello"); 

"привет" здесь не std::string. Это const char *.

Измените это к

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

И результат будет таким же, как класс таможни.

+1

Важная частью является то, что обертка шаблонная (так никакого принуждения не происходит в этом вызове), в то время как внутренняя функция не только принимает 'зОго :: string', что означает преобразование в' string' происходит затем (предоставляя ссылку r-значения на внутреннюю функцию), при этом не требуется переадресация. – ShadowRanger

+3

'' hello "' не является 'const char *', это 'const char [6]', который может распасться на 'const char *'. . –

+1

^(и не разрушается в этой ситуации) –

Смежные вопросы