std::reference_wrapper
Overview
std::reference_wrapper is a wrapper introduced in C++11 that wraps an lvalue reference into a copyable, assignable object. Plain references (T&) cannot be copied, assigned, or stored in standard containers. std::reference_wrapper solves this by holding an internal pointer to the target object, supporting copy and assignment semantics, while providing implicit conversion back to T&.
Header: <functional>
#include <functional>Basic Usage
Creating reference_wrapper
int x = 42;
std::reference_wrapper<int> r1 = std::ref(x); // recommended approach
std::reference_wrapper<int> r2(x); // direct construction
r1 = 99; // modify the original value through the wrapper
std::cout << x; // outputs 99std::ref() and std::cref()
int val = 10;
std::reference_wrapper<int> rw = std::ref(val); // mutable reference
std::reference_wrapper<const int> crw = std::cref(val); // const reference
val = 20;
std::cout << rw.get() << '\n'; // 20
// crw.get() = 30; // compile error: cannot modify through const referencestd::ref and std::cref are convenience factory functions that return std::reference_wrapper<T> and std::reference_wrapper<const T> respectively.
Implicit Conversion
std::reference_wrapper provides implicit conversion to T&, so most functions and algorithms that accept references can use it directly:
void increment(int& v) { ++v; }
int n = 5;
std::reference_wrapper<int> rw = std::ref(n);
increment(rw); // implicitly converts to int&
std::cout << n; // 6Storing References in Containers
Standard containers require elements to be copyable or movable. References themselves don't satisfy this requirement, but std::reference_wrapper does:
#include <vector>
#include <functional>
#include <iostream>
int main() {
int a = 1, b = 2, c = 3;
std::vector<std::reference_wrapper<int>> refs = {std::ref(a), std::ref(b), std::ref(c)};
for (auto& r : refs) {
r.get() *= 10; // modify original objects through the wrapper
}
std::cout << a << ' ' << b << ' ' << c << '\n'; // 10 20 30
}Storing References to Different Types
When using std::reference_wrapper, all elements in a container have the same type (reference_wrapper<int>). For heterogeneous references, use base class pointers or other mechanisms:
struct Base { int id = 0; };
struct Derived : Base { int extra = 42; };
Derived d;
std::reference_wrapper<Base> rw = std::ref(static_cast<Base&>(d));Usage with std::bind
std::bind internally uses std::reference_wrapper to preserve references to arguments. By default, std::bind copies its arguments; std::ref prevents this copy:
#include <functional>
#include <iostream>
void add_one(int& v) { ++v; }
int main() {
int value = 10;
auto bound = std::bind(add_one, std::ref(value));
bound(); // value is modified
std::cout << value; // 11
}// Without std::ref, bind copies the value
int value = 10;
auto bound = std::bind(add_one, value); // copies value
bound(); // modifies the copy, original value unchanged
std::cout << value; // 10 (unchanged)Cannot Bind to Rvalues
std::reference_wrapper can only bind to lvalues, not rvalues (temporary objects):
int x = 42;
std::reference_wrapper<int> r1 = std::ref(x); // OK
// std::reference_wrapper<int> r2 = std::ref(42); // compile error: cannot bind rvalue
// Also cannot bind to temporary objects
std::string temp() { return "hello"; }
// auto r3 = std::ref(temp()); // compile error: cannot bind to return value of temporaryReason: Allowing rvalue binding would result in a dangling reference, since temporaries are destroyed at the end of the expression.
reference_wrapper Members
| Member Function | Description |
|---|---|
get() | Returns T&, accesses the wrapped reference |
operator T&() | Implicit conversion to T& |
operator= | Assigns to the referenced object through the wrapper |
int x = 5, y = 10;
std::reference_wrapper<int> r1 = std::ref(x);
std::reference_wrapper<int> r2 = std::ref(y);
r1 = r2; // equivalent to x = y, x becomes 10
r1.get() = 100; // x = 100Code Examples
Generic Mutable View Container
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
template <typename T>
class MutableView {
std::vector<std::reference_wrapper<T>> refs_;
public:
void add(T& obj) { refs_.push_back(std::ref(obj)); }
void scale_all(double factor) {
for (auto& r : refs_) {
r.get() = static_cast<T>(r.get() * factor);
}
}
void print() const {
for (const auto& r : refs_) {
std::cout << r.get() << ' ';
}
std::cout << '\n';
}
};
int main() {
double a = 2.0, b = 3.0, c = 4.0;
MutableView<double> view;
view.add(a);
view.add(b);
view.add(c);
view.scale_all(10.0);
view.print(); // 20 30 40
std::cout << a << ' ' << b << ' ' << c << '\n'; // 20 30 40
}reference_wrapper as Callback Parameter
#include <functional>
#include <vector>
#include <iostream>
void process(std::function<void(int&)> callback, int& val) {
callback(val);
}
int main() {
int counter = 0;
auto increment = [](int& v) { ++v; };
auto double_val = [](int& v) { v *= 2; };
process(increment, counter);
process(double_val, counter);
std::cout << counter << '\n'; // 2
}Notes and Pitfalls
Do not hold reference_wrapper to temporary objects — while the compiler blocks std::ref(42), bypassing the type system via reinterpret_cast or other means may produce dangling references.
reference_wrapper is not nullptr-safe — it does not check whether the internal pointer is null:
std::reference_wrapper<int> r = std::ref(*static_cast<int*>(nullptr));
r.get(); // undefined behaviorconst correctness — std::ref deduces to reference_wrapper<T>, while std::cref deduces to reference_wrapper<const T>. Choose carefully:
int val = 0;
const auto& cr = std::cref(val); // const reference wrapper
// cr.get() = 5; // compile error
auto r = std::ref(val); // mutable reference wrapper
r.get() = 5; // OKCompiler Support
| Compiler | Supported Since | Notes |
|---|---|---|
| GCC | 4.5+ | Full support |
| Clang | 3.1+ | Full support |
| MSVC | 2012 (17.0)+ | Full support |
std::reference_wrapper is widely supported in C++11 and is the only mechanism in the standard library for placing references into containers. Its integration with std::bind makes it an important tool for functional programming styles in C++.