C++11coreintermediate
std::forward (C++11 Addition)
C++11 · Modern Revolution · Compiler flag: -std=c++11
Explanation
Preserves value category (lvalue/rvalue) in template forwarding.
Real-World Scenario
Write a generic wrapper function for a logging system.
Quick Snippet
snippet.cpp
template<typename T> void forward(T&& arg) { func(std::forward<T>(arg)); }Full Example
forward.cpp
// CodeNebula - C++11 Example: std::forward Usage Patterns
// Compile: g++ -std=c++11 -Wall -Wextra -o example forward.cpp
// Demonstrates std::forward usage patterns: the key utility for perfect
// forwarding. std::forward conditionally casts to an rvalue reference based
// on the deduced template parameter, preserving the original value category.
#include <iostream>
#include <string>
#include <utility>
#include <vector>
// Overloaded receiver to show which overload is called
void receive(const std::string& s)
{
std::cout << " receive(const&): \"" << s << "\"" << std::endl;
}
void receive(std::string&& s)
{
std::cout << " receive(&&): \"" << s << "\"" << std::endl;
}
// ------------------------------------------------------------------
// Pattern 1: Single-argument forwarding
// ------------------------------------------------------------------
template <typename T>
void relay(T&& arg)
{
receive(std::forward<T>(arg));
}
// ------------------------------------------------------------------
// Pattern 2: Forwarding into a container (emplace pattern)
// ------------------------------------------------------------------
template <typename T>
void addToVector(std::vector<std::string>& vec, T&& value)
{
vec.push_back(std::forward<T>(value));
}
// ------------------------------------------------------------------
// Pattern 3: Forwarding constructor arguments
// ------------------------------------------------------------------
class Wrapper {
std::string value_;
public:
template <typename T>
explicit Wrapper(T&& val) : value_(std::forward<T>(val))
{
std::cout << " Wrapper constructed: \"" << value_ << "\"" << std::endl;
}
const std::string& get() const { return value_; }
};
// ------------------------------------------------------------------
// Pattern 4: Forwarding multiple arguments
// ------------------------------------------------------------------
template <typename F, typename... Args>
void invoke(F&& func, Args&&... args)
{
std::forward<F>(func)(std::forward<Args>(args)...);
}
int main()
{
// ------------------------------------------------------------------
// Pattern 1: Value category preservation
// ------------------------------------------------------------------
std::cout << "=== Single-argument forwarding ===" << std::endl;
std::string name = "Alice";
relay(name); // T=string& -> forward keeps lvalue
relay(std::string("Bob")); // T=string -> forward casts to rvalue
relay(std::move(name)); // T=string -> forward casts to rvalue
std::cout << std::endl;
// ------------------------------------------------------------------
// Pattern 2: Emplace into container
// ------------------------------------------------------------------
std::cout << "=== Forwarding into vector ===" << std::endl;
std::vector<std::string> vec;
std::string item = "Lvalue item";
addToVector(vec, item); // copy into vector
addToVector(vec, std::string("Rvalue item")); // move into vector
for (const auto& s : vec) {
std::cout << " vec: \"" << s << "\"" << std::endl;
}
std::cout << std::endl;
// ------------------------------------------------------------------
// Pattern 3: Forwarding constructor
// ------------------------------------------------------------------
std::cout << "=== Forwarding constructor ===" << std::endl;
std::string data = "Shared";
Wrapper w1(data); // copies data
Wrapper w2(std::string("Temporary")); // moves temporary
std::cout << " w1: " << w1.get() << std::endl;
std::cout << " w2: " << w2.get() << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// Pattern 4: Forwarding into callable
// ------------------------------------------------------------------
std::cout << "=== Forwarding to callable ===" << std::endl;
auto printer = [](const std::string& a, int b) {
std::cout << " printer: \"" << a << "\", " << b << std::endl;
};
std::string arg1 = "test";
invoke(printer, arg1, 42);
invoke(printer, std::string("temp"), 99);
// ------------------------------------------------------------------
// Pattern 5: Why NOT to use std::move when you mean std::forward
// ------------------------------------------------------------------
std::cout << std::endl << "=== forward vs move ===" << std::endl;
std::cout << " forward: preserves the caller's intent" << std::endl;
std::cout << " move: always casts to rvalue (may steal from lvalues!)" << std::endl;
return 0;
}
/*
Expected output:
=== Single-argument forwarding ===
receive(const&): "Alice"
receive(&&): "Bob"
receive(&&): "Alice"
=== Forwarding into vector ===
vec: "Lvalue item"
vec: "Rvalue item"
=== Forwarding constructor ===
Wrapper constructed: "Shared"
Wrapper constructed: "Temporary"
w1: Shared
w2: Temporary
=== Forwarding to callable ===
printer: "test", 42
printer: "temp", 99
=== forward vs move ===
forward: preserves the caller's intent
move: always casts to rvalue (may steal from lvalues!)
*/
Run command
g++ -std=c++11 -Wall -Wextra -o example forward.cpp