乐闻世界logo
搜索文章和话题

What are the new features in C++11/14/17/20

2月18日 17:36

C++11/14/17/20 New Features

The C++ standard continues to evolve, with each new version introducing many powerful features that significantly improve development efficiency and code quality.

C++11 New Features

Automatic type deduction (auto):

cpp
// Automatic type deduction auto x = 42; // int auto y = 3.14; // double auto z = "Hello"; // const char* auto& ref = x; // int& auto&& universal = x; // int& (universal reference) // Used with iterators std::vector<int> vec = {1, 2, 3}; for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; } // Range-based for loop for (auto& val : vec) { val *= 2; }

Range-based for loop:

cpp
std::vector<int> vec = {1, 2, 3, 4, 5}; // Read-only iteration for (const auto& val : vec) { std::cout << val << " "; } // Modify iteration for (auto& val : vec) { val *= 2; } // Initializer list for (auto val : {1, 2, 3, 4, 5}) { std::cout << val << " "; }

Lambda expressions:

cpp
// Basic syntax auto lambda = [](int x, int y) { return x + y; }; // Capture variables int threshold = 10; auto filtered = [threshold](int x) { return x > threshold; }; // Reference capture int sum = 0; auto accumulate = [&sum](int x) { sum += x; }; // Mixed capture int a = 1, b = 2; auto mixed = [a, &b]() { return a + b; }; // Variadic lambda auto variadic = [](auto... args) { return (args + ... + 0); }; // Usage std::vector<int> vec = {5, 15, 25}; auto it = std::find_if(vec.begin(), vec.end(), filtered);

Smart pointers:

cpp
#include <memory> // unique_ptr - exclusive ownership auto ptr1 = std::make_unique<int>(42); auto ptr2 = std::move(ptr1); // Transfer ownership // shared_ptr - shared ownership auto shared1 = std::make_shared<int>(100); auto shared2 = shared1; // Reference count increases std::cout << shared1.use_count() << std::endl; // 2 // weak_ptr - weak reference std::weak_ptr<int> weak = shared1; if (auto locked = weak.lock()) { std::cout << *locked << std::endl; }

Rvalue references and move semantics:

cpp
class MyString { private: char* data; size_t size; public: MyString(const char* str = ""); MyString(const MyString& other); // Copy constructor MyString(MyString&& other) noexcept; // Move constructor MyString& operator=(const MyString& other); // Copy assignment MyString& operator=(MyString&& other) noexcept; // Move assignment }; // Usage MyString str1 = "Hello"; MyString str2 = std::move(str1); // Move instead of copy

nullptr:

cpp
// Before C++11 int* ptr1 = NULL; void func(int* ptr); void func(int value); func(NULL); // Ambiguous, might call func(int) // C++11 int* ptr2 = nullptr; func(nullptr); // Clearly calls func(int*)

constexpr:

cpp
// Compile-time constant constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); } constexpr int result = factorial(5); // Compile-time calculation // Literal type struct Point { constexpr Point(double x, double y) : x(x), y(y) {} constexpr double distance() const { return x * x + y * y; } double x, y; }; constexpr Point p(3.0, 4.0); constexpr double dist = p.distance(); // 25.0

C++14 New Features

Generic lambdas:

cpp
// C++11 auto add = [](int a, int b) { return a + b; }; // C++14 - generic lambda auto genericAdd = [](auto a, auto b) { return a + b; }; auto result1 = genericAdd(10, 20); // int auto result2 = genericAdd(3.14, 2.71); // double

Variable templates:

cpp
template <typename T> constexpr T pi = T(3.1415926535897932385); // Usage double d = pi<double>; float f = pi<float>;

Binary literals:

cpp
int binary = 0b1010; // 10 int octal = 012; // 10 int hex = 0xA; // 10

Function return type deduction:

cpp
// C++11 auto add(int a, int b) -> int { return a + b; } // C++14 - automatic return type deduction auto add(int a, int b) { return a + b; } // Complex return type auto getVector() { return std::vector<int>{1, 2, 3}; }

std::make_unique:

cpp
// C++11 auto ptr = std::unique_ptr<int>(new int(42)); // C++14 auto ptr = std::make_unique<int>(42);

C++17 New Features

Structured bindings:

cpp
std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}}; // Before C++17 for (auto it = myMap.begin(); it != myMap.end(); ++it) { int key = it->first; std::string value = it->second; } // C++17 for (const auto& [key, value] : myMap) { std::cout << key << ": " << value << std::endl; } // Tuple unpacking auto [x, y, z] = std::make_tuple(1, 2.0, "three");

if constexpr:

cpp
template <typename T> auto process(T value) { if constexpr (std::is_integral_v<T>) { return value * 2; } else if constexpr (std::is_floating_point_v<T>) { return value / 2; } else { return value; } } // Usage process(10); // 20 process(3.14); // 1.57

std::optional:

cpp
#include <optional> std::optional<int> divide(int a, int b) { if (b == 0) { return std::nullopt; } return a / b; } // Usage auto result = divide(10, 2); if (result) { std::cout << *result << std::endl; } else { std::cout << "Division by zero" << std::endl; } // Provide default value int value = result.value_or(0);

std::variant:

cpp
#include <variant> std::variant<int, double, std::string> value; value = 42; value = 3.14; value = "Hello"; // Access std::visit([](auto&& arg) { std::cout << arg << std::endl; }, value); // Check type if (std::holds_alternative<int>(value)) { int intValue = std::get<int>(value); }

std::any:

cpp
#include <any> std::any value = 42; value = 3.14; value = "Hello"; // Access if (value.type() == typeid(int)) { int intValue = std::any_cast<int>(value); }

Fold expressions:

cpp
// C++17 template <typename... Args> auto sum(Args... args) { return (args + ... + 0); } // Usage auto total = sum(1, 2, 3, 4, 5); // 15 // Left fold template <typename... Args> bool allTrue(Args... args) { return (args && ...); } // Right fold template <typename... Args> void printAll(Args... args) { (std::cout << ... << args) << std::endl; }

std::string_view:

cpp
#include <string_view> void printString(std::string_view str) { std::cout << str << std::endl; } // Usage std::string str = "Hello"; const char* cstr = "World"; printString(str); // OK printString(cstr); // OK printString("Test"); // OK, no need to create temporary string object

C++20 New Features

Concepts:

cpp
#include <concepts> // Define concept template <typename T> concept Integral = std::is_integral_v<T>; template <typename T> concept Sortable = requires(T t) { { t.begin() } -> std::same_as<typename T::iterator>; { t.end() } -> std::same_as<typename T::iterator>; }; // Use concept to constrain template template <Integral T> T add(T a, T b) { return a + b; } // requires clause template <typename T> requires std::is_integral_v<T> T multiply(T a, T b) { return a * b; } // Abbreviated syntax void process(Integral auto value) { std::cout << value << std::endl; }

Three-way comparison (Spaceship Operator):

cpp
struct Point { int x, y; // Automatically generate comparison operators auto operator<=>(const Point&) const = default; }; // Usage Point p1{1, 2}; Point p2{1, 3}; if (p1 < p2) { std::cout << "p1 < p2" << std::endl; } if (p1 == p2) { std::cout << "p1 == p2" << std::endl; }

Ranges library:

cpp
#include <ranges> #include <vector> #include <algorithm> std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // Filter even numbers auto evens = numbers | std::views::filter([](int n) { return n % 2 == 0; }); // Transform auto squared = numbers | std::views::transform([](int n) { return n * n; }); // Combined operations auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; }); // Usage for (auto n : result) { std::cout << n << " "; }

Coroutines:

cpp
#include <coroutine> // Simple generator template <typename T> struct Generator { struct promise_type { T current_value; Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(T value) { current_value = value; return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; std::coroutine_handle<promise_type> handle; Generator(std::coroutine_handle<promise_type> h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } bool next() { handle.resume(); return !handle.done(); } T value() { return handle.promise().current_value; } }; Generator<int> fibonacci() { int a = 0, b = 1; while (true) { co_yield a; int temp = a + b; a = b; b = temp; } } // Usage auto gen = fibonacci(); for (int i = 0; i < 10; ++i) { gen.next(); std::cout << gen.value() << " "; }

Modules:

cpp
// math.ixx (module interface) export module math; export int add(int a, int b) { return a + b; } export double multiply(double a, double b) { return a * b; } // main.cpp import math; int main() { int result = add(10, 20); return 0; }

std::format:

cpp
#include <format> std::string name = "Alice"; int age = 30; // Format string std::string message = std::format("Name: {}, Age: {}", name, age); // Formatted numbers double pi = 3.14159; std::string formatted = std::format("Pi: {:.2f}", pi); // Pi: 3.14 // Padding and alignment std::string padded = std::format("{:>10}", "Hello"); // " Hello"

Best Practices

1. Prefer auto for type deduction

cpp
// Recommended auto it = vec.begin(); auto result = std::make_unique<int>(42); // Not recommended std::vector<int>::iterator it = vec.begin(); std::unique_ptr<int> result(new int(42));

2. Use smart pointers to manage resources

cpp
// Recommended auto ptr = std::make_unique<Resource>(); // Not recommended Resource* ptr = new Resource();

3. Use nullptr instead of NULL

cpp
// Recommended int* ptr = nullptr; // Not recommended int* ptr = NULL;

4. Use constexpr for compile-time calculation

cpp
// Recommended constexpr int size = 1024; // Not recommended const int size = 1024;

5. Use range-based for loops

cpp
// Recommended for (const auto& val : vec) { std::cout << val << std::endl; } // Not recommended for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; }
标签:C++