Difference between revisions of "cpp/utility/functional/reference wrapper"
(Undo revision 73784 by 94.246.4.144 (talk) Appears I was wrong.) |
m (→Member types: fmt: +br=yes) |
||
(40 intermediate revisions by 19 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/utility/functional/reference_wrapper/navbar}} | {{cpp/utility/functional/reference_wrapper/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | functional }} | + | {{dcl header|functional}} |
− | {{dcl | since=c++11 | | + | {{dcl|since=c++11| |
template< class T > | template< class T > | ||
class reference_wrapper; | class reference_wrapper; | ||
Line 9: | Line 9: | ||
{{dcl end}} | {{dcl end}} | ||
− | {{tt|std::reference_wrapper}} is a class template that wraps a reference in a copyable, assignable object | + | {{tt|std::reference_wrapper}} is a class template that wraps a reference in a copyable, assignable object. |
− | Specifically, {{tt|std::reference_wrapper}} is a {{ | + | Specifically, {{tt|std::reference_wrapper}} is a {{named req|CopyConstructible}} and {{named req|CopyAssignable}} wrapper around a reference to object or reference to function of type {{tt|T}}. Instances of {{tt|std::reference_wrapper}} are objects (they can be copied or stored in containers) but they are implicitly convertible to {{c|T&}}, so that they can be used as arguments with the functions that take the underlying type by reference. |
− | + | If the stored reference is {{named req|Callable}}, {{tt|std::reference_wrapper}} is callable with the same arguments. | |
− | {{ | + | Helper functions {{lc|std::ref}} and {{lc|std::cref}} are often used to generate {{tt|std::reference_wrapper}} objects. |
− | {{ | + | {{tt|std::reference_wrapper}} is used to pass objects by reference to {{lc|std::bind}}, the constructor of {{lc|std::thread}}, or the helper functions {{lc|std::make_pair}} and {{lc|std::make_tuple}}. It can also be used as a mechanism to store references inside standard containers (like {{lc|std::vector}}) that cannot normally hold references. |
− | {{ | + | |
− | {{tt|std::reference_wrapper}} is {{ | + | {{rrev|since=c++17| |
+ | {{tt|std::reference_wrapper}} is guaranteed to be {{named req|TriviallyCopyable}}. | ||
+ | }} | ||
+ | |||
+ | {{rrev|since=c++20| | ||
+ | {{tt|T}} may be an incomplete type. | ||
}} | }} | ||
− | |||
===Member types=== | ===Member types=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc hitem | type | definition }} | + | {{dsc hitem|type|definition}} |
− | {{dsc | {{tt|type}} | {{tt|T}}}} | + | {{dsc|{{tt|type}}|{{tt|T}}}} |
− | {{dsc | {{tt|result_type}} | The return type of {{tt|T}} if {{tt|T}} is a function. Otherwise, not defined }} | + | {{dsc|{{tt|result_type}}<br>{{mark life|deprecated=c++17|removed=c++20|br=yes}}|The return type of {{tt|T}} if {{tt|T}} is a function. Otherwise, not defined.}} |
− | {{dsc | {{tt|argument_type}} | | + | {{dsc|{{tt|argument_type}}<br>{{mark life|deprecated=c++17|removed=c++20|br=yes}}| |
− | + | * if {{tt|T}} is a function or pointer to function that takes one argument of type {{tt|A1}}, then {{tt|argument_type}} is {{tt|A1}}<br> | |
− | + | * if {{tt|T}} is a pointer to member function of class {{tt|T0}} that takes no arguments, then {{tt|argument_type}} is {{c/core|T0*}}, possibly cv-qualified<br> | |
− | {{dsc | {{tt|first_argument_type}} | | + | * if {{tt|T}} is a class type with a member type {{c/core|T::argument_type}}, then {{tt|argument_type}} is an alias of that}} |
− | + | {{dsc|{{tt|first_argument_type}}<br>{{mark life|deprecated=c++17|removed=c++20|br=yes}}| | |
− | + | * if {{tt|T}} is a function or pointer to function that takes two arguments of types {{tt|A1}} and {{tt|A2}}, then {{tt|first_argument_type}} is {{tt|A1}}<br> | |
+ | * if {{tt|T}} is a pointer to member function of class {{tt|T0}} that takes one argument, then {{tt|first_argument_type}} is {{c/core|T0*}}, possibly cv-qualified<br> | ||
+ | * if {{tt|T}} is a class type with a member type {{c/core|T::first_argument_type}}, then {{tt|first_argument_type}} is an alias of that | ||
}} | }} | ||
− | {{dsc | {{tt|second_argument_type}} | | + | {{dsc|{{tt|second_argument_type}}<br>{{mark life|deprecated=c++17|removed=c++20|br=yes}}| |
− | + | * if {{tt|T}} is a function or pointer to function that takes two arguments of type s {{tt|A1}} and {{tt|A2}}, then {{tt|second_argument_type}} is {{tt|A2}}<br> | |
− | + | * if {{tt|T}} is a pointer to member function of class {{tt|T0}} that takes one argument {{tt|A1}}, then {{tt|second_argument_type}} is {{tt|A1}}, possibly cv-qualified<br> | |
+ | * if {{tt|T}} is a class type with a member type {{c/core|T::second_argument_type}}, then {{tt|second_argument_type}} is an alias of that}} | ||
{{dsc end}} | {{dsc end}} | ||
===Member functions=== | ===Member functions=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/utility/functional/reference_wrapper/dsc constructor}} | + | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc constructor}} |
− | {{dsc inc | cpp/utility/functional/reference_wrapper/dsc operator{{=}} }} | + | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc operator{{=}}}} |
− | {{dsc inc | cpp/utility/functional/reference_wrapper/dsc get}} | + | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc get}} |
− | {{dsc inc | cpp/utility/functional/reference_wrapper/dsc operator()}} | + | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc operator()}} |
{{dsc end}} | {{dsc end}} | ||
+ | |||
+ | ===Non-member functions=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc operator_cmp}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ==={{rl|deduction guides|Deduction guides}}{{mark since c++17}}=== | ||
+ | |||
+ | ===Helper classes=== | ||
+ | {{dsc begin}} | ||
+ | {{dsc inc|cpp/utility/functional/reference_wrapper/dsc basic_common_reference}} | ||
+ | {{dsc end}} | ||
+ | |||
+ | ===Possible implementation=== | ||
+ | {{eq fun | ||
+ | |1= | ||
+ | namespace detail | ||
+ | { | ||
+ | template<class T> constexpr T& FUN(T& t) noexcept { return t; } | ||
+ | template<class T> void FUN(T&&) = delete; | ||
+ | } | ||
+ | |||
+ | template<class T> | ||
+ | class reference_wrapper | ||
+ | { | ||
+ | public: | ||
+ | // types | ||
+ | using type = T; | ||
+ | |||
+ | // construct/copy/destroy | ||
+ | template<class U, class = decltype( | ||
+ | detail::FUN<T>(std::declval<U>()), | ||
+ | std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>() | ||
+ | )> | ||
+ | constexpr reference_wrapper(U&& u) | ||
+ | noexcept(noexcept(detail::FUN<T>(std::forward<U>(u)))) | ||
+ | : _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {} | ||
+ | |||
+ | reference_wrapper(const reference_wrapper&) noexcept = default; | ||
+ | |||
+ | // assignment | ||
+ | reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; | ||
+ | |||
+ | // access | ||
+ | constexpr operator T& () const noexcept { return *_ptr; } | ||
+ | constexpr T& get() const noexcept { return *_ptr; } | ||
+ | |||
+ | template<class... ArgTypes> | ||
+ | constexpr std::invoke_result_t<T&, ArgTypes...> | ||
+ | operator() (ArgTypes&&... args ) const | ||
+ | noexcept(std::is_nothrow_invocable_v<T&, ArgTypes...>) | ||
+ | { | ||
+ | return std::invoke(get(), std::forward<ArgTypes>(args)...); | ||
+ | } | ||
+ | |||
+ | private: | ||
+ | T* _ptr; | ||
+ | }; | ||
+ | |||
+ | // deduction guides | ||
+ | template<class T> | ||
+ | reference_wrapper(T&) -> reference_wrapper<T>; | ||
+ | }} | ||
===Example=== | ===Example=== | ||
{{example | {{example | ||
− | + | |Demonstrates the use of {{tt|std::reference_wrapper}} as a container of references, which makes it possible to access the same container using multiple indices. | |
− | + | |code= | |
#include <algorithm> | #include <algorithm> | ||
+ | #include <functional> | ||
+ | #include <iostream> | ||
#include <list> | #include <list> | ||
+ | #include <numeric> | ||
+ | #include <random> | ||
#include <vector> | #include <vector> | ||
− | + | ||
− | + | void println(auto const rem, std::ranges::range auto const& v) | |
+ | { | ||
+ | for (std::cout << rem; auto const& e : v) | ||
+ | std::cout << e << ' '; | ||
+ | std::cout << '\n'; | ||
+ | } | ||
int main() | int main() | ||
{ | { | ||
− | std::list<int> l | + | std::list<int> l(10); |
− | + | std::iota(l.begin(), l.end(), -4); | |
+ | |||
+ | // can't use shuffle on a list (requires random access), but can use it on a vector | ||
std::vector<std::reference_wrapper<int>> v(l.begin(), l.end()); | std::vector<std::reference_wrapper<int>> v(l.begin(), l.end()); | ||
− | |||
− | std:: | + | std::ranges::shuffle(v, std::mt19937{std::random_device{}()}); |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | println("Contents of the list: ", l); | |
− | + | println("Contents of the list, as seen through a shuffled vector: ", v); | |
− | + | ||
− | + | ||
− | + | ||
std::cout << "Doubling the values in the initial list...\n"; | std::cout << "Doubling the values in the initial list...\n"; | ||
− | + | std::ranges::for_each(l, [](int& i) { i *= 2; }); | |
− | + | ||
− | + | ||
− | + | println("Contents of the list, as seen through a shuffled vector: ", v); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | + | |p=true | |
− | Contents of the list: -4 -3 -2 -1 0 1 2 3 4 | + | |output= |
− | Contents of the list, shuffled: | + | Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5 |
+ | Contents of the list, as seen through a shuffled vector: -1 2 -2 1 5 0 3 -3 -4 4 | ||
Doubling the values in the initial list... | Doubling the values in the initial list... | ||
− | + | Contents of the list, as seen through a shuffled vector: -2 4 -4 2 10 0 6 -6 -8 8 | |
}} | }} | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/utility/functional/dsc ref}} | + | {{dsc inc|cpp/utility/functional/dsc ref}} |
− | {{dsc inc | cpp/utility/functional/dsc bind}} | + | {{dsc inc|cpp/utility/functional/dsc bind}} |
+ | {{dsc inc|cpp/utility/functional/dsc unwrap_reference}} | ||
{{dsc end}} | {{dsc end}} | ||
− | + | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Latest revision as of 02:04, 8 July 2024
Defined in header <functional>
|
||
template< class T > class reference_wrapper; |
(since C++11) | |
std::reference_wrapper
is a class template that wraps a reference in a copyable, assignable object.
Specifically, std::reference_wrapper
is a CopyConstructible and CopyAssignable wrapper around a reference to object or reference to function of type T
. Instances of std::reference_wrapper
are objects (they can be copied or stored in containers) but they are implicitly convertible to T&, so that they can be used as arguments with the functions that take the underlying type by reference.
If the stored reference is Callable, std::reference_wrapper
is callable with the same arguments.
Helper functions std::ref and std::cref are often used to generate std::reference_wrapper
objects.
std::reference_wrapper
is used to pass objects by reference to std::bind, the constructor of std::thread, or the helper functions std::make_pair and std::make_tuple. It can also be used as a mechanism to store references inside standard containers (like std::vector) that cannot normally hold references.
|
(since C++17) |
|
(since C++20) |
Contents |
[edit] Member types
type | definition |
type
|
T
|
result_type (deprecated in C++17) (removed in C++20) |
The return type of T if T is a function. Otherwise, not defined.
|
argument_type (deprecated in C++17) (removed in C++20) |
|
first_argument_type (deprecated in C++17) (removed in C++20) |
|
second_argument_type (deprecated in C++17) (removed in C++20) |
|
[edit] Member functions
stores a reference in a new std::reference_wrapper object (public member function) | |
rebinds a std::reference_wrapper (public member function) | |
accesses the stored reference (public member function) | |
calls the stored function (public member function) |
[edit] Non-member functions
(C++26) |
compares reference_wrapper objects as their stored references (function) |
[edit] Deduction guides(since C++17)
[edit] Helper classes
determines the common reference type of reference_wrapper and non-reference_wrapper (class template specialization) |
[edit] Possible implementation
namespace detail { template<class T> constexpr T& FUN(T& t) noexcept { return t; } template<class T> void FUN(T&&) = delete; } template<class T> class reference_wrapper { public: // types using type = T; // construct/copy/destroy template<class U, class = decltype( detail::FUN<T>(std::declval<U>()), std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>() )> constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u)))) : _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {} reference_wrapper(const reference_wrapper&) noexcept = default; // assignment reference_wrapper& operator=(const reference_wrapper& x) noexcept = default; // access constexpr operator T& () const noexcept { return *_ptr; } constexpr T& get() const noexcept { return *_ptr; } template<class... ArgTypes> constexpr std::invoke_result_t<T&, ArgTypes...> operator() (ArgTypes&&... args ) const noexcept(std::is_nothrow_invocable_v<T&, ArgTypes...>) { return std::invoke(get(), std::forward<ArgTypes>(args)...); } private: T* _ptr; }; // deduction guides template<class T> reference_wrapper(T&) -> reference_wrapper<T>; |
[edit] Example
Demonstrates the use of std::reference_wrapper
as a container of references, which makes it possible to access the same container using multiple indices.
#include <algorithm> #include <functional> #include <iostream> #include <list> #include <numeric> #include <random> #include <vector> void println(auto const rem, std::ranges::range auto const& v) { for (std::cout << rem; auto const& e : v) std::cout << e << ' '; std::cout << '\n'; } int main() { std::list<int> l(10); std::iota(l.begin(), l.end(), -4); // can't use shuffle on a list (requires random access), but can use it on a vector std::vector<std::reference_wrapper<int>> v(l.begin(), l.end()); std::ranges::shuffle(v, std::mt19937{std::random_device{}()}); println("Contents of the list: ", l); println("Contents of the list, as seen through a shuffled vector: ", v); std::cout << "Doubling the values in the initial list...\n"; std::ranges::for_each(l, [](int& i) { i *= 2; }); println("Contents of the list, as seen through a shuffled vector: ", v); }
Possible output:
Contents of the list: -4 -3 -2 -1 0 1 2 3 4 5 Contents of the list, as seen through a shuffled vector: -1 2 -2 1 5 0 3 -3 -4 4 Doubling the values in the initial list... Contents of the list, as seen through a shuffled vector: -2 4 -4 2 10 0 6 -6 -8 8
[edit] See also
(C++11)(C++11) |
creates a std::reference_wrapper with a type deduced from its argument (function template) |
(C++11) |
binds one or more arguments to a function object (function template) |
(C++20)(C++20) |
get the reference type wrapped in std::reference_wrapper (class template) |