Я учусь 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
? Если нет, что (может быть, что-то плохое) произойдет?
Важная частью является то, что обертка шаблонная (так никакого принуждения не происходит в этом вызове), в то время как внутренняя функция не только принимает 'зОго :: string', что означает преобразование в' string' происходит затем (предоставляя ссылку r-значения на внутреннюю функцию), при этом не требуется переадресация. – ShadowRanger
'' hello "' не является 'const char *', это 'const char [6]', который может распасться на 'const char *'. . –
^(и не разрушается в этой ситуации) –