- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
- Tips and Techniques
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
-
C++0X: The New Face of Standard C++
- Reference Wrapper
- The Performance Technical Report
- auto for the People
- Ironing Templates' Syntactic Wrinkles
- Visual C++ Becomes ISO Compliant
- A Garbage Collector for C++
- C99 Core Features in C++0X
- The <code>shared_ptr</code> Class
- The shared_ptr Class, II
- Lambda Expressions and Closures, Part I
- Lambda Expressions and Closures, Part II
- Lambda Expressions and Closures, Part III
- The Type Traits Library, Part I
- The Type Traits Library, Part II
- The Type Traits Library, Part III
- finally Revisited
- The Any Library
- The nullptr Keyword Proposal
- Delegating Constructors
- The Explicit Conversion Operators Proposal
- Conditionally-Supported Behavior
- The weak ptr Class Template, Part I
- The weak ptr Class Template, Part II
- POD Types Revisited
- The rvalue Reference Proposal, Part I
- The rvalue Reference Proposal, Part II
- Proposal for New String Algorithms
- Concepts, Part I
- Concepts, Part II
- constexpr: Generalized Constant Expressions
- The <u>constexpr</u> Proposal: Constructors
- Strongly-Typed enum Types
- C++09: The Road Ahead
- C++09: Proposals by Statuses
- Changing Undefined Behavior to Diagnosable Errors
- New Character Types
- The __func__ Predeclared Identifier is Coming to C++
- Static Assertions
- The extern template Proposal
- Variadic Templates, Part I
- Variadic Templates, Part II
- Variadic Templates, Part III -- Critique
- Using unique_ptr, Part I
- Using unique_ptr, Part II
- Unrestricted Unions, Part I
- Unrestricted Unions, Part II
- Unrestricted Unions, Part III
- Types With No Linkage as Template Arguments
- New Initialization Syntax
- Initializer Lists and Sequence Constructors
- New Standard Library Algorithms
- Class Member Initializers
- Inheriting Constructors
- Introducing Attributes
- The Removal of Concepts From C++0x
- The Future of C++0x, Part I
- The Future of C++0X, Part II
- The Debate About Attributes, Part I
- The Debate About Attributes, Part II
- The Debate About Attributes, Part III
- The Debate About Attributes, Part IV
- Forward Declarations of Enum Types
- The SCARY Iterators Proposal, Part I
- The SCARY Iterators Proposal, Part II
- Heading for Deprecation: <tt>export</tt>, Exception Specification and <tt>register</tt>
- The Rejection of the Unified Function Syntax Proposal
- Rvalue References as Object Members
- FCD Approved
- The Debate on noexcept, Part I
- The Debate on noexcept, Part II
- The Debate on noexcept, Part III
- About-face -- [[Attributes]] to Be Replaced with Keywords
- Will Delegating Constructors Be Removed From C++0x?
- Rvalue References: Past, Present and Future, Part I
- Rvalue References: Past, Present and Future, Part II
- Rvalue References: Past, Present and Future, Part III
- A Move in the Right Direction, Part I
- A Move in the Right Direction, Part II
- New Keywords for Inheritance Control, Part I
- New Keywords for Inheritance Control, Part II
- FDIS Approved
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
Reference Wrapper
Last updated Jan 1, 2003.
Continuing our journey into the new C++ standard, this time I present another proposal that has been incorporated into the Library Extensions Technical Report: the reference wrapper class.
Rationale
In certain contexts, built-in reference types cannot be used as first class citizens in C++.
For example, you can't define a container of references:
std::vector <int &> vri; //won't compile
In this respect, reference types are different from bare pointers, which can be used as container elements. Additionally, it is sometimes necessary to pass references as arguments to algorithms and functions that would usually create a copy of their arguments.
A reference wrapper class template enables you to wrap a reference in the guise of an object. The object can then be used in contexts in which built-in references won't work. Consider the following example:
void func(int & r)
{
r++;
}
template<class F, class T> void g(F f, T t)
{
f(t);
}
int main()
{
int i = 0;
g(func, i);
}
The second parameter of g() is passed by value. To force g() to take a reference instead, a reference wrapper can do the trick.
The reference_wrapper Class Template
reference_wrapper<T> is a copy-constructible and assignable wrapper around an object of type T&. The copy-constructible and assignable properties ensure, among other things, that reference_wrapper object can be used as an element of STL containers.
The reference_wrapper class and its helper functions are declared in the <utility> header. This header, as you probably know, already contains several other facilities such as auto_ptr.
There are two helper functions: ref() and cref() create a reference_wrapper object that wraps their argument. cref() returns a const T& wrapper object whereas ref() returns a T& wrapper object.
NOTE
When dealing with plain references and references to const objects, people often use the term "const reference" when they actually mean a reference to a const object. Notice that there's no point in having a const reference in C++ in the first place because a reference, once initialized, can't be bound to a different object.
Notice how the use of a reference_wrapper helps us ensure that the function template g() behaves as if it took a reference rather than a copy of its argument:
int main()
{
int i = 0;
g(f, i); //pass i by value
cout << i << endl; //as expected, 0
g(f, ref(i)); //bind a reference to i and pass it as arg
cout << i << endl; // output: 1
}
Let's look at what this program does. First, the function g() is called with two arguments that are passed by value: a function pointer and a copy of i. g() in turns invokes the function bound to f, which increments the copy of i. As expected, when g() returns, the change to the local copy of i ins't reflected in the i that was declared in main(). Therefore, the first cout expression displays 0. In the second call to g(), the ref() helper function creates a temporary reference_warpper() that is bound to i. The side effects of func() are therefore reflected in i after the call and the second cout expression displays 1.
reference_wrapper can be used where ordinary references cannot, such as in containers:
std::list<int> num; std::vector<reference_wrapper<int> > num_refs; // a list of references to int
for(int i = 0; i < 10; ++i)
{
numbers.push_back(2*i*i^4 - 8*i + 7); //ordinary copy semantics
num_refs.push_back(
//create a reference to the last element in nums
ref(numbers.back()));
}
A reference_wrapper enables you to pass T& as an argument to algorithms that expect the underlying type, i.e., T:
std::sort(num_refs.begin(), num_refs.end());
Using reference_wrapper with Tuples
reference_wrapper also enables you to create tuples of references and references to const in cases where the tuple class would use the underlying, non-cv-qualified type instead:
void f(const A& ca, B& b)
{
make_tuple(ca, b); // returns tuple<A, B>
}
To override the default behavior of make_tuple, use ref() and cref() like this:
A a; B b; const A ca=a; make_tuple( cref(a), b); // tuple <const A&, B> (a,b) make_tuple( ref(a), b); // tuple <A&, B> (a,b) make_tuple( ref(a), cref(b) ); // tuple <A&, const B&> (a,b)
Summary
The reference_wrapper utility class and its helper functions exemplify how a small library can be neatly incorporated into C++ to fill a few syntactic lacunae. This type of solution is preferable because it guarantees that existing compilers can cope with new C++ code without requiring upgrades and more importantly -- without causing existing code to break.
