У меня есть несколько вопросов относительно этой программы:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
Выход:
false
Я хочу знать, если std::ref
не возвращает ссылку на объект, тогда что он делает? По сути, в чем разница между:
T x;
auto r = ref(x);
а также
T x;
T &y = x;
Кроме того, я хочу знать, почему существует эта разница? Зачем нам std::ref
или же std::reference_wrapper
когда у нас есть ссылки (т.е. T&
)?
Что ж ref
конструирует объект соответствующего reference_wrapper
тип для хранения ссылки на объект. Что означает, когда вы подаете заявление:
auto r = ref(x);
Это возвращение reference_wrapper
& не прямая ссылка на x (ie T&)
, это reference_wrapper (ie r)
вместо этого держит T&
,
reference_wrapper
очень полезно, когда вы хотите подражать reference
объекта, который может быть скопирован (это как copy-constructible
а также copy-assignable
).
В C ++, когда вы создаете reference (say y)
для object (say x)
, затем y
& x
делить то же самое base address
, Более того, y
не может ссылаться на любой другой объект. Также вы не можете создать array of references
то есть код, подобный этому, выдаст ошибку:
#include <iostream>
using namespace std;
int main()
{
int x=5, y=7, z=8;
int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references
return 0;
}
Однако это законно:
#include <iostream>
#include <functional> // for reference_wrapper
using namespace std;
int main()
{
int x=5, y=7, z=8;
reference_wrapper<int> arr[] {x,y,z};
for (auto a:arr)
cout<<a<<" ";
return 0;
}
/* OUTPUT :-
5 7 8
*/
Говоря о вашей проблеме с cout<<is_same<T&,decltype(r)>::value;
, решение: —
cout<<is_same<T&,decltype(r.get())>::value; // will yield true
Позвольте мне показать вам программу: —
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
int main()
{
cout<<boolalpha;
int x=5, y=7;;
reference_wrapper<int> r=x; // or auto r = ref(x);
cout<<is_same<int&, decltype(r.get())>::value<<"\n";
cout<<(&x==&r.get())<<"\n";
r=y;
cout<<(&y==&r.get())<<"\n";
r.get()=70;
cout<<y;
return 0;
}
/* Ouput :-
true
true
true
70
*/
Смотрите здесь, мы узнаем три вещи:
reference_wrapper
объект (здесь r
) может быть использован для создания array of references
что было невозможно с T&
,
r
на самом деле действует как настоящий reference
( Смотри как r.get()=70
изменил значение y
).
r
не то же самое, что T&
но r.get()
является. Это означает, что r
держит T&
то есть как следует из названия это wrapper around reference T&
,
Я надеюсь, что этого ответа более чем достаточно, чтобы объяснить ваши сомнения.
std::reference_wrapper
признается стандартными средствами, чтобы иметь возможность передавать объекты по ссылке в контексте передачи по значению.
Например, std::bind
может взять в std::ref()
передайте его по значению и позже распакуйте обратно в ссылку.
void print(int i) {
std::cout << i << '\n';
}
int main() {
int i = 10;
auto f1 = std::bind(print, i);
auto f2 = std::bind(print, std::ref(i));
i = 20;
f1();
f2();
}
Этот фрагмент выводит:
10
20
Значение i
был сохранен (взят по значению) в f1
в тот момент, когда он был инициализирован, но f2
сохранил std::reference_wrapper
по стоимости, и, следовательно, ведет себя так, как это потребовалось в int&
,
Ссылка (T&
или же T&&
) является специальным элементом в языке C ++. Это позволяет манипулировать объектом по ссылке и имеет особые случаи использования на языке. Например, вы не можете создать стандартный контейнер для хранения ссылок: vector<T&>
плохо сформирован и генерирует ошибку компиляции.
std::reference_wrapper
с другой стороны, это объект C ++, способный содержать ссылку. Таким образом, вы можете использовать его в стандартных контейнерах.
std::ref
это стандартная функция, которая возвращает std::reference_wrapper
на его аргумент. В той же идее std::cref
возвращается std::reference_wrapper
к постоянной ссылке.
Одно интересное свойство std::reference_wrapper
что у него есть operator T& () const noexcept;
, Это означает, что даже если это настоящий объект, он может быть автоматически преобразован в ссылку, которую он держит. Так:
operator T& () const noexcept;
, он может быть использован везде, где вы можете использовать ссылку, потому что он будет автоматически преобразован в него.