Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.73/15: Рейтинг темы: голосов - 15, средняя оценка - 4.73
13 / 13 / 2
Регистрация: 13.09.2013
Сообщений: 113
1

Зачем в определении std::forward () нужен объект remove_reference?

29.08.2014, 23:28. Просмотров 2913. Ответов 12
Метки нет (Все метки)

Зачем в определении std::forward() нужен объект remove_reference ? И почему не могут быть выведены аргументы шаблона? Я написал вот такой вот код,все отлично работает,в обоих случаях возвращается rvalue, вызываются соотв. ф-и go,для lvalue и rvalue соответственно:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;
 
 
 
template <class T>  //для lvalue
T&& go(T& x )
{
    return static_cast<T&&>(x);
}
 
template <class T >
T&& go(T&& x)                  //rvalue
{
    return static_cast<T&&>(x);
}
 
class Huston
{
    int a;
public:
    Huston(int& f) :a(f)
    {
 
    }
    Huston(int&& b) :a(move(b))
    {
 
    }
};
int func(int b ){ return b; }
int main()
{
    
    int b = 3;
    Huston a(go(b));//move constructor is called
    Huston c(go(2));//move constructor is called
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.08.2014, 23:28
Ответы с готовыми решениями:

Зачем нужен std::map
Почитал информацию об этом классе, но так и не понял, зачем он нужен?

Зачем нужен std::launder?
Зачем нужен std::launder?

Зачем оператору lock в качестве параметра нужен объект (object)
Зачем оператору lock в качестве параметра нужен объект (object) lock (lockObject) { //... }

Применение std::forward
Хочу сделать внутри метода большой обьект. Затем передать его через return. Для этого хочу...

12
В астрале
Эксперт С++
8028 / 4785 / 654
Регистрация: 24.06.2010
Сообщений: 10,558
30.08.2014, 01:35 2
TheChosenOne, Работает? Какой компилятор? https://ideone.com/65ZM8S

Добавлено через 28 минут
А дело все в reference-collapse. Советую почитать ответ на этот вопрос на SO: http://stackoverflow.com/quest... rward-work
0
13 / 13 / 2
Регистрация: 13.09.2013
Сообщений: 113
30.08.2014, 02:53  [ТС] 3
ForEveR, IDE: MVS 13, стандартный сl.
С collapsing rules я знаком уже
Не могу понять, задача forward() сохранить аргумент (т.е если передали ему lvalue ref он должен вернуть lvalue) или его задача вернуть rvalue? У меня компилятор возвращает rvalue всегда.
C++
1
2
int  b =3; //lvalue
Huston temp(forward<int>(b));// тут вызывается конструктор и семантикой перемещения
0
1172 / 885 / 94
Регистрация: 03.08.2011
Сообщений: 2,455
30.08.2014, 03:30 4
Как то так.
Returns an rvalue reference to arg if arg is not an lvalue reference.

If arg is an lvalue reference, the function returns arg without modifying its type.
Добавлено через 1 минуту
То есть, если агрумент не является lvalue, то возвращается rvalue. Если аргумент - lvalue, то функция ничего не меняет и возвращает его.
1
Эксперт С++
1661 / 1033 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
30.08.2014, 10:41 5
Если всегда нужен rvalue-reference, так это делается обычным static_cast или вызовом std::move (в котором точно такой же static_cast).
1
В астрале
Эксперт С++
8028 / 4785 / 654
Регистрация: 24.06.2010
Сообщений: 10,558
30.08.2014, 13:11 6
TheChosenOne, Вы не совсем логично используете std::forward. Его не имеет смысла использовать просто так с конкретными типами. Тут в соседней теме скидывали линк на тему piecewise_construct, но там и про forward прекрасно описано: http://thbecker.net/articles/r... on_08.html
Цитата оттуда, как раз про ваш вопрос:
If you want to dig a little deeper for extra credit, ask yourself this question: why is the remove_reference in the definition of std::forward needed? The answer is, it is not really needed at all. If you use just S& instead of remove_reference<S>::type& in the defintion of std::forward, you can repeat the case distinction above to convince yourself that perfect forwarding still works just fine. However, it works fine only as long as we explicitly specify Arg as the template argument of std::forward. The purpose of the remove_reference in the definition of std::forward is to force us to do so.
1
13 / 13 / 2
Регистрация: 13.09.2013
Сообщений: 113
30.08.2014, 15:12  [ТС] 7
Цитата Сообщение от ForEveR Посмотреть сообщение
However, it works fine only as long as we explicitly specify Arg as the template argument of std::forward. The purpose of the remove_reference in the definition of std::forward is to force us to do so.
Вот этот момент интересует.Не пойму зачем указывать параметр шаблона явно...
Вот,например: Если просто передать rvalue ( без указания параметра шаблона ) получается разрешается так:
C++
1
S&& && -> S&&
Если передать lvalue ,тогда вот так:
C++
1
S& && ->S&
т.е. все работает и без явного указания параметра шаблона. Где будет неправильный вывод аргумента?
0
Эксперт С++
1661 / 1033 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
30.08.2014, 19:39 8
Rvalue reference "сбрасывается" при обычном форвардинге. Если мы имеем функцию template <class T> fwd(T&& x) {foo(x);} то функция foo (опять же, если она шаблонная и работает type deduction) увидит не T&&, а просто T.
1
Игогошка!
1799 / 706 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
30.08.2014, 19:43 9
Цитата Сообщение от TheChosenOne Посмотреть сообщение
Зачем в определении std::forward() нужен объект remove_reference ?
Подставь типы T и T& и посмотри, что будет без него. А будет совсем не так, как задумывалось.

Цитата Сообщение от TheChosenOne Посмотреть сообщение
И почему не могут быть выведены аргументы шаблона?
Он конечно может, но как forward тогда корректно определить, является ли твоя lvalue - lvalue reference или rvalue reference?

И еще раз:
1) forward имеет смысл использовать только с универсальными ссылками, потому что именно для них есть особое правило: выведенный тип при вызове функции для lvalue будет T&, а для rvalue будет T.
2) rvalue references вполне могут быть lvalue.
1
13 / 13 / 2
Регистрация: 13.09.2013
Сообщений: 113
30.08.2014, 20:06  [ТС] 10
Nick Alte, Вы,скорее всего не поняли вопрос. Вот,допустим я написал свой "forward<T>()" ,его задача передать аргумент,сохранив его тип. Но мой forward() будет использовать type deducing:
C++
1
2
3
4
5
template <class T >
T&& go(T&& x)
{
    return static_cast<T&&>(x);
}
Когда передаю ему lvalue , он возвращает lvalue. Когда передаю rvalue, он возвращает rvalue. Вроде бы как и должен работать ? Тогда зачем в std::forward() используется явная параметризация шаблона? Если и без нее можно было написать ф-ю, которая сама будет выводить шаблонный параметр и работать при этом корректно (или она все же работает некорректно,но в каком случае? ) ?

Добавлено через 3 минуты
ct0r, Тип Т ? Выводится всегда Т& (lvalue) или T&& (rvalue), разве это некорректно ? Универсальные ссылки,это шаблонные ссылки ?
0
Эксперт С++
1661 / 1033 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
30.08.2014, 20:18 11
Лучший ответ Сообщение было отмечено TheChosenOne как решение

Решение

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <functional>
 
using namespace std;
 
template <class T>  // lvalue
T&& go(T& x )
{
    return static_cast<T&&>(x);
}
 
template <class T >
T&& go(T&& x)                  //rvalue
{
    return static_cast<T&&>(x);
}
 
void foo(int& x)
{
    cout << "lvalue reference" << endl;
}
 
void foo(int&& x)
{
    cout << "rvalue reference" << endl;
}
 
template<typename T>
void fwd(T&& x)
{
    foo(x);
//    foo(go(x));
    foo(std::forward<T>(x));
}
 
int main()
{
    int x = 0;
    fwd(x);
    fwd(7);
    return 0;
}
Раскомментируем строчку с вызовом go и получим тот самый случай, когда работать не будет.

Добавлено через 5 минут
P.S. По совместительству этот случай - как раз то, для чего std::forward и сделали.
1
Игогошка!
1799 / 706 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
30.08.2014, 20:21 12
Цитата Сообщение от TheChosenOne Посмотреть сообщение
Тип Т ? Выводится всегда Т& (lvalue) или T&& (rvalue), разве это некорректно ? Универсальные ссылки,это шаблонные ссылки ?
C++
1
2
3
4
5
template <typename T>
int foo(T&& k)
 
foo(2) - T == int
foo(n) - T == int&
Не вижу смысла в использовании твоей функции go. Как она определит, lvalue, которое я передаю в go, является на самом деле rvalue ref или lvalue ref?
1
13 / 13 / 2
Регистрация: 13.09.2013
Сообщений: 113
30.08.2014, 22:45  [ТС] 13
Nick Alte, все,теперь я понял,спасибо ) Действительно,внутри другой ф-и rvalue ссылка есть lvalue
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.08.2014, 22:45

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

C++11 - std::forward и static_assert
Привет. Эта тема создана в познавательных целях. А именно, мне не совсем понятна реализация...

Зачем часто писать std::, если можно один раз using namespace std?
зачем часто писать std:: если можно один раз using namespace std?

В каком случае используется вторая перегрузка std::forward?
В каком случае используется втарая перегрузка std::forward? //clang 3.8.0 #include...

Зачем в определении функции заново задаются переменные
Есть программа для перевода из Цельсия в фарингейты На грамматические ошибки не обращайте...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.