C++14
A small but important refinement of C++11. Generic lambdas make callables reusable. std::make_unique fills the obvious gap. Relaxed constexpr removes the single-expression restriction. The standard that said "we got C++11 right — now let's fix the rough edges."
Core Language
Lambda parameters can be auto, making the lambda a template. Avoids the verbosity of writing explicit template syntax for short callables.
#include <algorithm>
#include <vector>
// C++11 — must specify type
auto add_int = [](int a, int b) { return a + b; };
// C++14 — auto parameters, works for any type
auto add = [](auto a, auto b) { return a + b; };
add(1, 2); // int
add(1.5, 2.5); // double
add(std::string{"hello"}, std::string{" world"}); // string
// Generic sort comparator
std::sort(v.begin(), v.end(),
[](const auto& a, const auto& b) { return a < b; });constexpr functions can now contain local variables, loops, and if statements. No longer limited to single-expression functions.
// C++11 — constexpr limited to single return expression
constexpr int factorial11(int n) {
return n <= 1 ? 1 : n * factorial11(n-1);
}
// C++14 — loops and local variables allowed
constexpr int factorial14(int n) {
int result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
constexpr int f10 = factorial14(10); // 3628800, computed at compile timeRegular functions can deduce their return type from return statements. Eliminates trailing return type syntax for simple cases.
// C++11 — required explicit return type or trailing type
auto add11(int a, int b) -> int { return a + b; }
// C++14 — deduced from return statement
auto add14(int a, int b) { return a + b; } // deduced as int
// Useful for complex expression types
auto make_pair_of_pairs(auto a, auto b) {
return std::make_pair(std::make_pair(a, b), std::make_pair(b, a));
}
// Return type would be very verbose to write manuallyTemplates can now define variables. Eliminates the ::value pattern for type traits and enables cleaner numeric constants.
// Compile-time constant templated on type
template<typename T>
constexpr T pi = T{3.141592653589793};
float pi_f = pi<float>; // 3.14159f
double pi_d = pi<double>; // 3.14159265358979
// Simplify type traits
template<typename T>
constexpr bool is_integral_v = std::is_integral<T>::value;
// C++14 still required ::value; C++17 added _v helpers to stdlib
static_assert(is_integral_v<int>);Capture variables by move, or initialize captures with arbitrary expressions. Enables move-only types in lambda captures.
#include <memory>
#include <string>
// Move a unique_ptr into a lambda (impossible in C++11)
auto ptr = std::make_unique<Widget>();
auto lambda = [p = std::move(ptr)]() {
p->use(); // lambda owns the unique_ptr
};
// Capture with computed initial value
int x = 42;
auto fn = [y = x * 2]() { return y; };
fn(); // 84Library
The missing factory function from C++11. Creates a unique_ptr safely — no raw new, exception-safe, explicit about ownership.
#include <memory>
// C++11 — had to use raw new (exception-unsafe in some cases)
std::unique_ptr<Widget> p11(new Widget(arg1, arg2));
// C++14 — exception-safe, no raw new
auto p14 = std::make_unique<Widget>(arg1, arg2);
// Array form
auto arr = std::make_unique<int[]>(100);
// Rule: never call new directly; use make_unique/make_sharedReplaces a value and returns the old value. Clean idiom for move constructors and building new values from old ones.
#include <utility>
// In a move constructor — reset source after moving
class Buffer {
int* data_;
std::size_t size_;
public:
Buffer(Buffer&& other) noexcept
: data_{std::exchange(other.data_, nullptr)}
, size_{std::exchange(other.size_, 0)}
{}
};
// General idiom: process old value, set new value
int old_count = std::exchange(count_, 0); // reset and get old
process(old_count);std::map::find and std::set::find can accept compatible comparison keys (e.g., string_view for string maps) without constructing a key object.
#include <map>
#include <string>
// Use std::less<void> (or std::less<>) as comparator
std::map<std::string, int, std::less<>> scores;
scores["Alice"] = 95;
// No std::string construction — lookup with string_view or const char*
auto it = scores.find("Alice"); // no temporary string constructed
auto it2 = scores.find(std::string_view{"Alice"}); // sameA compile-time sequence of integers. Enables calling functions with tuple elements as individual arguments (std::apply, C++17).
#include <utility>
#include <tuple>
#include <functional>
// Call f with tuple elements as separate args
template<typename F, typename Tuple, std::size_t... I>
auto apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template<typename F, typename Tuple>
auto apply(F&& f, Tuple&& t) {
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
// std::apply (C++17) is the standard version of this0b prefix for binary literals. Single-quote separator in numeric literals for readability — works with int, float, hex.
// Binary literals
constexpr int flags = 0b1010'1100; // 172
constexpr int mask = 0b0000'1111; // 15
// Digit separators — any numeric literal
constexpr long long BILLION = 1'000'000'000LL;
constexpr double AVOGADRO = 6.022'140'76e23;
constexpr int HEX_ADDR = 0xDEAD'BEEF;
// Useful for bit masks and hardware register values
constexpr unsigned CTRL_REG = 0b0001'0100'0011'0010;