Okay, this is a fun challenge! Listing all features is a monumental task, as there are many small library additions and tweaks. I'll focus on the most impactful language and standard library features introduced in C++11, C++14, and C++17, with examples geared towards a Video-on-Demand (VoD) application.
Let's imagine we're building components for "StreamFlix," our new VoD service.
C++11 was a massive update.
-
autoKeyword (Type Inference)- Description: Allows the compiler to deduce the type of a variable from its initializer.
- StreamFlix Example: Iterating through a list of movies.
#include <vector> #include <string> #include <iostream> struct Movie { std::string title; int releaseYear; }; int main() { std::vector<Movie> catalog = {{"Inception", 2010}, {"The Matrix", 1999}}; auto it = catalog.begin(); // it is std::vector<Movie>::iterator std::cout << "First movie: " << it->title << std::endl; auto firstMovie = catalog[0]; // firstMovie is Movie std::cout << "Also: " << firstMovie.title << std::endl; return 0; }
-
Range-Based
forLoops- Description: Simplifies iterating over elements in a range (e.g., containers, arrays).
- StreamFlix Example: Displaying all movie titles in a user's watchlist.
#include <vector> #include <string> #include <iostream> struct Movie { std::string title; }; int main() { std::vector<Movie> watchlist = {{"Pulp Fiction"}, {"Parasite"}}; std::cout << "Your Watchlist:\n"; for (const auto& movie : watchlist) { // auto& is efficient std::cout << "- " << movie.title << std::endl; } return 0; }
-
Lambda Expressions
- Description: Allow defining anonymous functions (closures) inline.
- StreamFlix Example: Sorting movies by release year or finding a movie by title.
#include <vector> #include <string> #include <algorithm> #include <iostream> struct Movie { std::string title; int releaseYear; }; int main() { std::vector<Movie> catalog = {{"Inception", 2010}, {"The Matrix", 1999}}; // Sort by release year std::sort(catalog.begin(), catalog.end(), [](const Movie& a, const Movie& b) { return a.releaseYear < b.releaseYear; }); std::cout << "Sorted by year:\n"; for (const auto& movie : catalog) { std::cout << movie.title << " (" << movie.releaseYear << ")\n"; } // Find a specific movie std::string targetTitle = "Inception"; auto foundMovieIt = std::find_if(catalog.begin(), catalog.end(), [&targetTitle](const Movie& m) { // Capture targetTitle by reference return m.title == targetTitle; }); if (foundMovieIt != catalog.end()) { std::cout << "Found: " << foundMovieIt->title << std::endl; } return 0; }
-
nullptr- Description: A type-safe null pointer constant, replacing
NULLor0. - StreamFlix Example: Checking if a user's profile data has been loaded.
#include <iostream> struct UserProfile { std::string username; /* ... */ }; UserProfile* getCurrentUserProfile() { // In a real app, this would fetch data return nullptr; // Simulate no user logged in } int main() { UserProfile* profile = getCurrentUserProfile(); if (profile == nullptr) { std::cout << "No user logged in. Please sign in to StreamFlix." << std::endl; } else { std::cout << "Welcome, " << profile->username << "!" << std::endl; } return 0; }
- Description: A type-safe null pointer constant, replacing
-
Smart Pointers (
std::unique_ptr,std::shared_ptr,std::weak_ptr)- Description: Manage dynamic memory automatically, preventing memory leaks.
- StreamFlix Example:
unique_ptrfor a video decoder,shared_ptrfor movie metadata shared across UI elements.#include <memory> #include <string> #include <iostream> #include <vector> class VideoDecoder { // Base class for decoders public: virtual ~VideoDecoder() = default; virtual void decodeFrame() = 0; }; class H264Decoder : public VideoDecoder { public: H264Decoder() { std::cout << "H264Decoder created.\n"; } ~H264Decoder() { std::cout << "H264Decoder destroyed.\n"; } void decodeFrame() override { std::cout << "Decoding H.264 frame...\n"; } }; struct MovieMetadata { std::string title; std::string description; MovieMetadata(std::string t, std::string d) : title(t), description(d) { std::cout << "Metadata for '" << title << "' created.\n"; } ~MovieMetadata() { std::cout << "Metadata for '" << title << "' destroyed.\n"; } }; int main() { // Unique ownership: only one part of the code owns the decoder std::unique_ptr<VideoDecoder> decoder = std::make_unique<H264Decoder>(); if (decoder) { decoder->decodeFrame(); } // decoder goes out of scope, H264Decoder is automatically destroyed // Shared ownership: metadata can be accessed by multiple parts std::shared_ptr<MovieMetadata> inceptionData = std::make_shared<MovieMetadata>("Inception", "A mind-bending thriller."); std::vector<std::shared_ptr<MovieMetadata>> uiElementsData; uiElementsData.push_back(inceptionData); // UIs share the same data uiElementsData.push_back(inceptionData); std::cout << "Accessing from UI 1: " << uiElementsData[0]->title << std::endl; // Metadata destroyed when all shared_ptrs go out of scope. return 0; }
-
Move Semantics (Rvalue References,
std::move)- Description: Allows efficient transfer of resources from one object to another, avoiding costly copies.
- StreamFlix Example: Efficiently assigning a large downloaded video buffer to a player.
#include <vector> #include <string> #include <utility> // For std::move #include <iostream> class VideoBuffer { public: std::vector<unsigned char> data; VideoBuffer(size_t size) : data(size) { std::cout << "VideoBuffer of size " << size << " constructed.\n"; } VideoBuffer(const VideoBuffer& other) : data(other.data) { std::cout << "VideoBuffer copied.\n"; } VideoBuffer(VideoBuffer&& other) noexcept : data(std::move(other.data)) { std::cout << "VideoBuffer moved.\n"; } // ... other members }; VideoBuffer downloadVideoChunk() { VideoBuffer chunk(1024 * 1024 * 10); // 10MB chunk // Simulate filling buffer with data return chunk; // Return by value, eligible for move } int main() { VideoBuffer playerBuffer(0); std::cout << "Before assignment:\n"; playerBuffer = downloadVideoChunk(); // Move assignment will be used std::cout << "After assignment: Player buffer size " << playerBuffer.data.size() << "\n"; return 0; }
-
constexpr- Compile-time Expressions- Description: Allows expressions and functions to be evaluated at compile time.
- StreamFlix Example: Defining a maximum number of recommendations or a default bitrate.
#include <iostream> constexpr int MAX_RECOMMENDATIONS = 10; constexpr int DEFAULT_HD_BITRATE_KBPS = 5000; constexpr int calculateBufferSize(int seconds, int bitrate_kbps) { return (seconds * bitrate_kbps * 1024) / 8; // Bytes } int main() { int recommendations[MAX_RECOMMENDATIONS]; // Array size known at compile time std::cout << "Max recommendations: " << MAX_RECOMMENDATIONS << std::endl; std::cout << "Default HD Bitrate: " << DEFAULT_HD_BITRATE_KBPS << " kbps\n"; constexpr int bufferFor10SecHD = calculateBufferSize(10, DEFAULT_HD_BITRATE_KBPS); std::cout << "Buffer for 10s HD video: " << bufferFor10SecHD << " bytes\n"; return 0; }
-
Initializer Lists (
std::initializer_list)- Description: Provides a uniform way to initialize objects with a list of values.
- StreamFlix Example: Initializing a list of supported video formats.
#include <vector> #include <string> #include <initializer_list> #include <iostream> class SupportedCodecs { public: std::vector<std::string> codecs; SupportedCodecs(std::initializer_list<std::string> list) : codecs(list) {} void print() const { std::cout << "Supported Codecs by StreamFlix:\n"; for(const auto& codec : codecs) { std::cout << "- " << codec << std::endl; } } }; int main() { SupportedCodecs ourCodecs = {"H.264", "H.265", "AV1", "VP9"}; ourCodecs.print(); return 0; }
-
static_assert- Compile-time Assertions- Description: Perform assertions at compile time; if false, compilation fails.
- StreamFlix Example: Ensuring a struct used for network messages has a specific size.
#include <cstdint> // Packet structure for sending playback commands (e.g., play, pause) struct PlaybackCommand { uint8_t command_id; uint32_t timestamp; uint16_t sequence_number; // char padding[1]; // Uncomment to make it fail }; // Ensure our network protocol structure is exactly 8 bytes for compatibility. static_assert(sizeof(PlaybackCommand) == 7, "PlaybackCommand size is not 7 bytes!"); int main() { // Code using PlaybackCommand... return 0; }
-
Type Traits (
<type_traits>)- Description: Provides compile-time information about types.
- StreamFlix Example: Generic function to serialize metadata, behaving differently for numeric vs. string types.
#include <type_traits> #include <string> #include <iostream> template<typename T> void serialize_metadata_field(const std::string& key, const T& value) { if constexpr (std::is_integral_v<T>) { // C++17 if constexpr, for C++11 use SFINAE or tag dispatch std::cout << "Serializing integral field '" << key << "': " << value << std::endl; } else if constexpr (std::is_same_v<T, std::string>) { std::cout << "Serializing string field '" << key << "': \"" << value << "\"\n"; } else { std::cout << "Serializing unknown field type for '" << key << "'\n"; } } // C++11 way (using SFINAE for overload selection) template<typename T> typename std::enable_if<std::is_integral<T>::value>::type serialize_field_cpp11(const std::string& key, const T& value) { std::cout << "(C++11) Serializing integral field '" << key << "': " << value << std::endl; } template<typename T> typename std::enable_if<std::is_same<T, std::string>::value>::type serialize_field_cpp11(const std::string& key, const T& value) { std::cout << "(C++11) Serializing string field '" << key << "': \"" << value << "\"\n"; } int main() { serialize_metadata_field("episode_count", 24); serialize_metadata_field("genre", std::string("Sci-Fi")); serialize_field_cpp11("rating_stars", 5); serialize_field_cpp11("director_name", std::string("Nolan")); return 0; }
-
Variadic Templates
- Description: Templates that can take a variable number of arguments.
- StreamFlix Example: A logging function that can accept various arguments.
#include <iostream> #include <string> void log_event(const std::string& event_type) { std::cout << "[LOG] Event: " << event_type << std::endl; } template<typename T, typename... Args> void log_event(const std::string& event_type, T first_arg, Args... rest_args) { std::cout << "[LOG] Event: " << event_type << ", Arg: " << first_arg; // Simplified: just print first arg, then indicate more. A real one would print all. if constexpr (sizeof...(rest_args) > 0) { std::cout << " (+ " << sizeof...(rest_args) << " more args)" << std::endl; // Recursive call could be: log_event_details(rest_args...); } else { std::cout << std::endl; } } // For full printing: void print_args() { std::cout << std::endl; } // Base case for recursion template<typename T, typename... Args> void print_args(T first, Args... rest) { std::cout << first << " "; print_args(rest...); // Recursive call } template<typename... Args> void log_event_full(const std::string& event_type, Args... args) { std::cout << "[FULL LOG] Event: " << event_type << " | Data: "; print_args(args...); } int main() { log_event("UserLogin", "user123"); log_event("PlaybackStarted", "movie_id_789", "1080p", 0.75 /* volume */); log_event_full("PlaybackError", "E_NETWORK_TIMEOUT", "stream_url_xyz", 5000 /*ms*/); return 0; }
-
Threading Library (
<thread>,<mutex>,<future>, etc.)- Description: Standardized support for multithreading.
- StreamFlix Example: Downloading a video in a background thread.
#include <thread> #include <mutex> #include <chrono> #include <iostream> #include <string> std::mutex cout_mutex; // To protect std::cout void downloadVideo(std::string videoId, int* progress) { { std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Starting download for video: " << videoId << std::endl; } for (int i = 0; i <= 100; i += 10) { std::this_thread::sleep_for(std::chrono::milliseconds(200)); *progress = i; { std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Download " << videoId << ": " << *progress << "%" << std::endl; } } { std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Download complete for video: " << videoId << std::endl; } } int main() { int downloadProgress = 0; std::thread downloaderThread(downloadVideo, "matrix_4_trailer", &downloadProgress); // Main thread can do other things, like update UI while (downloadProgress < 100) { { std::lock_guard<std::mutex> lock(cout_mutex); std::cout << "Main thread: Checking progress... " << downloadProgress << "%" << std::endl; } std::this_thread::sleep_for(std::chrono::milliseconds(500)); } downloaderThread.join(); // Wait for the download thread to finish std::cout << "Main thread: Downloader finished." << std::endl; return 0; }
-
std::chrono- Time Utilities- Description: Library for handling time durations, time points, and clocks.
- StreamFlix Example: Measuring how long a video segment takes to buffer.
#include <chrono> #include <thread> #include <iostream> void simulateBufferSegment() { std::this_thread::sleep_for(std::chrono::milliseconds(150)); } int main() { auto startTime = std::chrono::high_resolution_clock::now(); simulateBufferSegment(); // Simulate work auto endTime = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime); std::cout << "Buffering segment took: " << duration.count() << " microseconds." << std::endl; return 0; }
-
std::function- Polymorphic Function Wrapper- Description: A general-purpose type that can store, copy, and invoke any callable target (function, lambda, bind expression, functor).
- StreamFlix Example: Setting a callback for when a "Play" button is clicked.
#include <functional> #include <string> #include <iostream> struct Movie { std::string title; }; class PlayButton { public: std::function<void(const Movie&)> onClick; // Callback void press(const Movie& movieToPlay) { if (onClick) { onClick(movieToPlay); } } }; void startPlayback(const Movie& movie) { std::cout << "Starting playback for: " << movie.title << std::endl; } int main() { PlayButton button; Movie selectedMovie = {"Interstellar"}; button.onClick = startPlayback; // Assign a free function button.press(selectedMovie); button.onClick = [&](const Movie& m) { // Assign a lambda std::cout << "Lambda: Now playing '" << m.title << "' on your big screen!" << std::endl; }; button.press(selectedMovie); return 0; }
-
std::tuple- Description: A fixed-size collection of heterogeneous values.
- StreamFlix Example: Returning multiple details about a movie from a function.
#include <tuple> #include <string> #include <iostream> // Returns: Title, Director, Release Year std::tuple<std::string, std::string, int> getMovieDetails(int movieId) { if (movieId == 1) { return std::make_tuple("Blade Runner 2049", "Denis Villeneuve", 2017); } return std::make_tuple("Unknown Movie", "N/A", 0); } int main() { auto movieInfo = getMovieDetails(1); std::cout << "Title: " << std::get<0>(movieInfo) << std::endl; std::cout << "Director: " << std::get<1>(movieInfo) << std::endl; std::cout << "Year: " << std::get<2>(movieInfo) << std::endl; return 0; }
-
Regular Expressions (
<regex>)- Description: Support for regular expression matching.
- StreamFlix Example: Validating a user's search query format.
#include <regex> #include <string> #include <iostream> bool isValidSearchQuery(const std::string& query) { // Example: Allow alphanumeric, spaces, hyphens. Min 3 chars. std::regex query_regex("^[a-zA-Z0-9\\s-]{3,}$"); return std::regex_match(query, query_regex); } int main() { std::string searchQuery1 = "Sci-Fi movies"; std::string searchQuery2 = "S!"; // Too short, invalid char std::cout << "'" << searchQuery1 << "' is valid: " << (isValidSearchQuery(searchQuery1) ? "true" : "false") << std::endl; std::cout << "'" << searchQuery2 << "' is valid: " << (isValidSearchQuery(searchQuery2) ? "true" : "false") << std::endl; return 0; }
-
overrideandfinalSpecifiers- Description:
overrideensures a virtual function is indeed overriding a base class method.finalprevents further overriding of a virtual function or inheritance from a class. - StreamFlix Example: Defining different types of user accounts.
#include <string> #include <iostream> class UserAccount { public: virtual std::string getSubscriptionType() const { return "Basic"; } virtual void displayFeatures() const { std::cout << "Basic features: SD streaming.\n"; } virtual ~UserAccount() = default; }; class PremiumUserAccount final : public UserAccount { // 'final' class cannot be inherited from public: std::string getSubscriptionType() const override { return "Premium"; } // 'override' check void displayFeatures() const override { std::cout << "Premium features: 4K streaming, downloads.\n"; } }; // class UltraPremiumUserAccount : public PremiumUserAccount {}; // ERROR: PremiumUserAccount is final int main() { UserAccount basicUser; PremiumUserAccount premiumUser; std::cout << "Basic user: " << basicUser.getSubscriptionType() << std::endl; basicUser.displayFeatures(); std::cout << "Premium user: " << premiumUser.getSubscriptionType() << std::endl; premiumUser.displayFeatures(); return 0; }
- Description:
-
defaultanddeletefor Special Member Functions- Description: Explicitly request compiler-generated special member functions (
=default) or prevent their generation (=delete). - StreamFlix Example: Making a
VideoStreamclass non-copyable.#include <iostream> #include <string> class VideoStream { public: std::string streamUrl; VideoStream(std::string url) : streamUrl(std::move(url)) { std::cout << "VideoStream for " << streamUrl << " opened.\n"; } ~VideoStream() { std::cout << "VideoStream for " << streamUrl << " closed.\n"; } // Prevent copying, as a stream is a unique resource VideoStream(const VideoStream&) = delete; VideoStream& operator=(const VideoStream&) = delete; // Allow moving VideoStream(VideoStream&& other) noexcept : streamUrl(std::move(other.streamUrl)) { std::cout << "VideoStream for " << streamUrl << " moved.\n"; other.streamUrl.clear(); // Ensure the moved-from object is in a valid state } VideoStream& operator=(VideoStream&& other) noexcept { if (this != &other) { streamUrl = std::move(other.streamUrl); other.streamUrl.clear(); std::cout << "VideoStream for " << streamUrl << " move-assigned.\n"; } return *this; } }; int main() { VideoStream stream1("rtsp://server/movie1"); // VideoStream stream2 = stream1; // COMPILE ERROR: copy constructor is deleted VideoStream stream3 = std::move(stream1); // OK: move constructor std::cout << "Stream1 URL after move: " << stream1.streamUrl << std::endl; return 0; }
- Description: Explicitly request compiler-generated special member functions (
-
Strongly-Typed Enums (
enum class)- Description: Enumerations whose enumerators are scoped and don't implicitly convert to integers.
- StreamFlix Example: Defining playback states.
#include <iostream> enum class PlaybackState { Playing, Paused, Stopped, Buffering, Error }; enum class VideoQuality { SD, HD, UHD4K }; void setPlaybackState(PlaybackState state) { if (state == PlaybackState::Playing) { std::cout << "StreamFlix: Playback started." << std::endl; } else if (state == PlaybackState::Paused) { std::cout << "StreamFlix: Playback paused." << std::endl; } // ... other states } int main() { PlaybackState currentState = PlaybackState::Paused; // int stateInt = currentState; // COMPILE ERROR: no implicit conversion setPlaybackState(currentState); setPlaybackState(PlaybackState::Playing); VideoQuality quality = VideoQuality::HD; // if (currentState == quality) {} // COMPILE ERROR: different enum types return 0; }
-
noexceptSpecifier and Operator- Description:
noexceptspecifier indicates a function will not throw exceptions.noexceptoperator checks if an expression can throw. - StreamFlix Example: Marking a simple getter as non-throwing.
#include <string> #include <iostream> #include <utility> // For std::move class MovieDetails { std::string m_title; public: MovieDetails(std::string title) : m_title(std::move(title)) {} // This getter is simple and won't throw. const std::string& getTitle() const noexcept { return m_title; } // Destructors are implicitly noexcept(true) in C++11 unless specified otherwise or member/base dtors can throw ~MovieDetails() noexcept { /* clean up, guaranteed not to throw */ } // Example of noexcept operator void risky_operation() {} // might throw void safe_swap(MovieDetails& other) noexcept(noexcept(std::swap(m_title, other.m_title))) { std::swap(m_title, other.m_title); // std::string::swap is noexcept } }; int main() { MovieDetails movie("Dune"); std::cout << "Movie: " << movie.getTitle() << std::endl; std::cout << "getTitle is noexcept: " << std::boolalpha << noexcept(movie.getTitle()) << std::endl; // true MovieDetails otherMovie("Oppenheimer"); std::cout << "safe_swap is noexcept: " << std::boolalpha << noexcept(movie.safe_swap(otherMovie)) << std::endl; // true return 0; }
- Description:
C++14 built upon C++11, adding mostly smaller features and conveniences.
-
Generic Lambdas
- Description: Lambda parameters can be declared with
auto, making them templates. - StreamFlix Example: A generic "add to favorites" function that works for
MovieorTVShowobjects (if they have agetId()method).#include <string> #include <iostream> #include <set> struct Movie { int id; std::string title; int getId() const { return id; } }; struct TVShow { int id; std::string name; int getId() const { return id; } }; std::set<int> favoriteMovieIds; std::set<int> favoriteShowIds; int main() { auto addToFavorites = [](const auto& mediaItem, std::set<int>& favSet) { favSet.insert(mediaItem.getId()); std::cout << "Added item with ID " << mediaItem.getId() << " to favorites." << std::endl; }; Movie m = {101, "Avatar"}; TVShow s = {202, "Stranger Things"}; addToFavorites(m, favoriteMovieIds); addToFavorites(s, favoriteShowIds); return 0; }
- Description: Lambda parameters can be declared with
-
Lambda Capture Initializers (Generalized Lambda Capture)
- Description: Allows creating new variables within the lambda capture clause, useful for moving objects into lambdas or more complex captures.
- StreamFlix Example: Moving a
unique_ptrto aDownloadTaskinto a lambda for asynchronous execution.#include <memory> #include <string> #include <iostream> #include <functional> // For std::function class DownloadTask { public: std::string url; DownloadTask(std::string u) : url(std::move(u)) { std::cout << "DownloadTask for " << url << " created.\n"; } void execute() { std::cout << "Executing download for " << url << std::endl; } ~DownloadTask() { std::cout << "DownloadTask for " << url << " destroyed.\n"; } }; int main() { auto task_ptr = std::make_unique<DownloadTask>("http://streamflix.com/movie.mp4"); // Move task_ptr into the lambda. The lambda now owns it. std::function<void()> async_task = [task = std::move(task_ptr)]() { if (task) { task->execute(); } }; // task_ptr is now nullptr here async_task(); // Simulate running it later // When async_task (and its captured 'task') is destroyed, DownloadTask is destroyed. return 0; }
-
autoReturn Type Deduction for Functions- Description: The return type of a normal function can be deduced by the compiler from its
returnstatements (all return statements must deduce to the same type). - StreamFlix Example: A factory function that creates different types of player UI elements.
#include <string> #include <iostream> struct BasicPlayerUI { void render() { std::cout << "Rendering Basic Player UI\n"; } }; struct AdvancedPlayerUI { void render() { std::cout << "Rendering Advanced Player UI\n"; } }; // Note: C++14 auto return type requires all return paths to yield compatible types. // This example is slightly contrived; usually used when the return type is complex or templated. // For genuinely different types, std::variant (C++17) or a base class pointer would be better. auto createPlayerUI_impl(bool useAdvanced) { if (useAdvanced) { // return AdvancedPlayerUI{}; // This would cause an error if BasicPlayerUI is also returned directly // as they are different types. We'd need a common base or variant. // For this simple example, let's assume we're just returning a message. return std::string("Advanced UI selected"); } else { return std::string("Basic UI selected"); } } // Better example with templates: template<typename T> auto process_data(T val) { // Return type depends on T return val * 2.5; // e.g., if T is int, returns double } int main() { auto ui_type_msg = createPlayerUI_impl(true); std::cout << ui_type_msg << std::endl; auto result = process_data(10); // result is double std::cout << "Processed data: " << result << std::endl; return 0; }
- Description: The return type of a normal function can be deduced by the compiler from its
-
constexprRelaxations- Description: More constructs are allowed in
constexprfunctions (e.g., local variables, loops, if statements). - StreamFlix Example: A more complex compile-time calculation for optimal streaming segment size.
#include <iostream> // C++14 allows more complex logic in constexpr functions constexpr int calculateOptimalSegmentDuration(int networkSpeedMbps) { int durationSec = 2; // Start with a base if (networkSpeedMbps < 5) { durationSec = 4; // Slower network, larger segments to reduce overhead } else if (networkSpeedMbps > 50) { durationSec = 1; // Faster network, smaller segments for quicker start } // Could have loops here too in C++14 int adjustment = 0; for(int i = 0; i < networkSpeedMbps / 10; ++i) { if (durationSec > 1) adjustment--; // a bit silly, just for demo } return durationSec + (adjustment/10); } int main() { constexpr int durationForSlowNet = calculateOptimalSegmentDuration(3); constexpr int durationForFastNet = calculateOptimalSegmentDuration(100); std::cout << "Optimal segment for 3Mbps: " << durationForSlowNet << "s\n"; std::cout << "Optimal segment for 100Mbps: " << durationForFastNet << "s\n"; return 0; }
- Description: More constructs are allowed in
-
std::make_unique- Description: Similar to
std::make_shared, provides a safe and convenient way to createstd::unique_ptrs. (Technically a library addition, but very important). - StreamFlix Example: Creating a
unique_ptrfor aVideoPlayerinstance.#include <memory> #include <string> #include <iostream> class VideoPlayer { std::string currentMovie; public: VideoPlayer() { std::cout << "VideoPlayer created.\n"; } ~VideoPlayer() { std::cout << "VideoPlayer destroyed.\n"; } void loadMovie(const std::string& title) { currentMovie = title; std::cout << "Loaded: " << title << std::endl; } }; int main() { // Before C++14 (or without std::make_unique): // std::unique_ptr<VideoPlayer> player1(new VideoPlayer()); // With C++14 std::make_unique: auto player2 = std::make_unique<VideoPlayer>(); // Simpler, exception-safe player2->loadMovie("Gladiator"); // player2 is automatically destroyed when it goes out of scope return 0; }
- Description: Similar to
-
Variable Templates
- Description: Allows defining templates for variables.
- StreamFlix Example: Defining a platform-dependent max texture size for UI rendering.
#include <iostream> // Assume we have some way to know the platform at compile time (simplified) #define PLATFORM_DESKTOP 1 #define PLATFORM_MOBILE 2 #define CURRENT_PLATFORM PLATFORM_DESKTOP template<int Platform> constexpr int max_texture_size_kb = 2048; // Default template<> // Specialization for mobile constexpr int max_texture_size_kb<PLATFORM_MOBILE> = 1024; // C++14 Variable Template for PI template<typename T> constexpr T pi = T(3.1415926535897932385L); int main() { std::cout << "Max texture size for current platform: " << max_texture_size_kb<CURRENT_PLATFORM> << "KB" << std::endl; std::cout << "Pi for float: " << pi<float> << std::endl; std::cout << "Pi for double: " << pi<double> << std::endl; return 0; }
-
Binary Literals and Digit Separators
- Description: Binary literals (
0bor0B) for integers. Digit separators (') for numeric literals to improve readability. - StreamFlix Example: Defining bit flags for video features or large timeout values.
#include <iostream> #include <cstdint> const uint8_t FEATURE_HDR = 0b00000001; // High Dynamic Range const uint8_t FEATURE_DOLBY_VISION = 0b00000010; const uint8_t FEATURE_SURROUND_SOUND = 0b00000100; const long network_timeout_ms = 15'000; // 15,000 milliseconds const int max_buffer_size_bytes = 100'000'000; // 100 MB int main() { uint8_t videoFeatures = FEATURE_HDR | FEATURE_SURROUND_SOUND; if (videoFeatures & FEATURE_HDR) { std::cout << "HDR is enabled.\n"; } std::cout << "Network timeout: " << network_timeout_ms << "ms\n"; std::cout << "Max buffer size: " << max_buffer_size_bytes << " bytes\n"; return 0; }
- Description: Binary literals (
-
[[deprecated]]Attribute- Description: Marks an entity as deprecated, causing a compiler warning if used.
- StreamFlix Example: Deprecating an old API for fetching movie recommendations.
#include <vector> #include <string> #include <iostream> [[deprecated("Use getPersonalizedRecommendationsV2() instead for better results.")]] std::vector<std::string> getOldRecommendations(int userId) { std::cout << "Called deprecated getOldRecommendations for user " << userId << std::endl; return {"Generic Movie 1", "Generic Movie 2"}; } std::vector<std::string> getPersonalizedRecommendationsV2(int userId) { // New fancy recommendation logic return {"Tailored Movie A for " + std::to_string(userId), "Tailored Movie B"}; } int main() { auto recs = getOldRecommendations(123); // Compiler warning here for (const auto& r : recs) std::cout << r << std::endl; return 0; }
C++17 brought another set of significant features.
-
Structured Bindings
- Description: Allows decomposing objects like pairs, tuples, arrays, and structs into individual named variables.
- StreamFlix Example: Getting movie ID, title, and genre from a tuple or struct.
#include <tuple> #include <string> #include <map> #include <iostream> struct MovieInfo { int id; std::string title; std::string genre; }; MovieInfo getMovieById(int id) { if (id == 42) return {42, "The Hitchhiker's Guide", "Sci-Fi Comedy"}; return {0, "Unknown", "Unknown"}; } int main() { // Decomposing a struct auto [movieId, movieTitle, movieGenre] = getMovieById(42); std::cout << "ID: " << movieId << ", Title: " << movieTitle << ", Genre: " << movieGenre << std::endl; // Decomposing a std::pair (e.g., from a map iteration) std::map<int, std::string> userWatchProgress = {{101, "01:30:00"}, {102, "00:15:32"}}; for (const auto& [contentId, progress] : userWatchProgress) { std::cout << "Content ID: " << contentId << " at " << progress << std::endl; } return 0; }
-
if constexpr- Description: A compile-time
ifstatement that discards branches not taken, based on a compile-time condition. - StreamFlix Example: A template function to process media items, with different logic for
AudioTrackvs.VideoTrack.#include <string> #include <iostream> struct AudioTrack { std::string codec = "AAC"; static constexpr bool hasVideo = false; void process() { std::cout << "Processing audio track with codec: " << codec << std::endl; } }; struct VideoTrack { std::string codec = "H.265"; int resolution_width = 1920; static constexpr bool hasVideo = true; void process() { std::cout << "Processing video track (" << codec << ") at " << resolution_width << "p" << std::endl; } }; template<typename MediaType> void configureStream(MediaType& media) { media.process(); if constexpr (MediaType::hasVideo) { // This code only compiles if MediaType::hasVideo is true std::cout << "Video specific configuration: Setting up renderer.\n"; // std::cout << media.resolution_width; // This would be valid here } else { // This code only compiles if MediaType::hasVideo is false std::cout << "Audio specific configuration: Setting up audio output device.\n"; // std::cout << media.resolution_width; // This would be a COMPILE ERROR here if AudioTrack has no resolution_width } } int main() { AudioTrack audio; VideoTrack video; configureStream(audio); configureStream(video); return 0; }
- Description: A compile-time
-
std::optional- Description: Represents an optional value; it can either contain a value or be empty.
- StreamFlix Example: A function that tries to find a user's subtitle preference, which might not exist.
#include <optional> #include <string> #include <iostream> #include <map> std::map<int, std::string> userSubtitlePrefs = {{123, "English"}, {456, "Spanish"}}; std::optional<std::string> getSubtitlePreference(int userId) { auto it = userSubtitlePrefs.find(userId); if (it != userSubtitlePrefs.end()) { return it->second; // Contains a value } return std::nullopt; // Empty } int main() { int currentUser = 123; int newUser = 789; if (auto pref = getSubtitlePreference(currentUser); pref.has_value()) { std::cout << "User " << currentUser << " preference: " << pref.value() << std::endl; } else { std::cout << "User " << currentUser << " has no subtitle preference set. Defaulting to off.\n"; } std::cout << "User " << newUser << " preference: " << getSubtitlePreference(newUser).value_or("English (default)") << std::endl; return 0; }
-
std::variant- Description: A type-safe union; it can hold a value from a set of specified alternative types.
- StreamFlix Example: A media player event that can be a
PlaybackStarted,PlaybackPaused, orErrorOccurredevent.#include <variant> #include <string> #include <iostream> struct PlaybackStartedEvent { std::string movieId; }; struct PlaybackPausedEvent { int pausePositionMs; }; struct ErrorOccurredEvent { int errorCode; std::string message; }; using PlayerEvent = std::variant<PlaybackStartedEvent, PlaybackPausedEvent, ErrorOccurredEvent>; void handlePlayerEvent(const PlayerEvent& event) { std::visit([](const auto& specificEvent) { using T = std::decay_t<decltype(specificEvent)>; if constexpr (std::is_same_v<T, PlaybackStartedEvent>) { std::cout << "Event: Playback Started for movie ID: " << specificEvent.movieId << std::endl; } else if constexpr (std::is_same_v<T, PlaybackPausedEvent>) { std::cout << "Event: Playback Paused at " << specificEvent.pausePositionMs << "ms" << std::endl; } else if constexpr (std::is_same_v<T, ErrorOccurredEvent>) { std::cout << "Event: Error " << specificEvent.errorCode << " - " << specificEvent.message << std::endl; } }, event); } int main() { PlayerEvent e1 = PlaybackStartedEvent{"inception_2010"}; PlayerEvent e2 = ErrorOccurredEvent{503, "Network unavailable"}; handlePlayerEvent(e1); handlePlayerEvent(e2); return 0; }
-
std::any- Description: A type-safe container for a single value of any copyable type.
- StreamFlix Example: Storing arbitrary plugin configuration values (e.g., a string for API key, an int for max connections).
#include <any> #include <string> #include <map> #include <iostream> int main() { std::map<std::string, std::any> streamflixPluginConfig; streamflixPluginConfig["drm_plugin_path"] = std::string("/usr/lib/drm/widevine.so"); streamflixPluginConfig["max_concurrent_downloads"] = 5; streamflixPluginConfig["enable_experimental_codec"] = true; // Retrieve and use a value if (auto it = streamflixPluginConfig.find("max_concurrent_downloads"); it != streamflixPluginConfig.end()) { try { int maxDownloads = std::any_cast<int>(it->second); std::cout << "Max concurrent downloads: " << maxDownloads << std::endl; } catch (const std::bad_any_cast& e) { std::cerr << "Error casting max_concurrent_downloads: " << e.what() << std::endl; } } if (auto it = streamflixPluginConfig.find("enable_experimental_codec"); it != streamflixPluginConfig.end()) { // Safe check before casting if (it->second.type() == typeid(bool)) { bool useExperimental = std::any_cast<bool>(it->second); std::cout << "Use experimental codec: " << std::boolalpha << useExperimental << std::endl; } } return 0; }
-
std::string_view- Description: A non-owning, read-only view of a character sequence (a string). Avoids copying string data.
- StreamFlix Example: Parsing movie titles or descriptions from a large manifest file without making copies.
#include <string_view> #include <string> #include <iostream> // Function that processes a subtitle line, doesn't need to own the string void displaySubtitleLine(std::string_view line) { // In a real app, this might send to a renderer std::cout << "Subtitle: " << line << std::endl; } int main() { std::string fullSubtitleFile = "1\n00:00:20,000 --> 00:00:22,500\nStreamFlix Presents\n\n2\n..."; // Imagine parsing this file std::string_view firstLine(fullSubtitleFile.c_str() + 26, 17); // Points to "StreamFlix Presents" displaySubtitleLine(firstLine); displaySubtitleLine("A new adventure begins!"); // Also works with string literals // Substring without allocation std::string_view movieTitle = "The Grand Budapest Hotel"; std::string_view grand = movieTitle.substr(4, 5); // "Grand" std::cout << "Substring: " << grand << std::endl; return 0; }
-
Parallel Algorithms (Execution Policies)
- Description: Many standard library algorithms gained overloads that accept an execution policy (e.g.,
std::execution::parfor parallel execution). - StreamFlix Example: Sorting a large catalog of movies in parallel.
#include <vector> #include <string> #include <algorithm> #include <execution> // For std::execution::par #include <iostream> #include <random> // For generating test data struct Movie { int id; std::string title; float rating; }; int main() { std::vector<Movie> catalog; // Populate with a lot of movies (e.g., 1,000,000) std::mt19937 rng(std::random_device{}()); std::uniform_real_distribution<float> dist(1.0, 5.0); for (int i = 0; i < 100000; ++i) { // Reduced for quicker demo catalog.push_back({i, "Movie " + std::to_string(i), dist(rng)}); } std::cout << "Sorting " << catalog.size() << " movies by rating...\n"; auto startTime = std::chrono::high_resolution_clock::now(); // Sort in parallel (if supported by implementation and beneficial for data size) std::sort(std::execution::par, catalog.begin(), catalog.end(), [](const Movie& a, const Movie& b) { return a.rating > b.rating; // Sort descending by rating }); auto endTime = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); std::cout << "Sorting took: " << duration.count() << " ms.\n"; // std::cout << "Top 5 movies:\n"; // for(int i=0; i<5 && i < catalog.size(); ++i) // std::cout << catalog[i].title << " - Rating: " << catalog[i].rating << std::endl; return 0; }
- Description: Many standard library algorithms gained overloads that accept an execution policy (e.g.,
-
Filesystem Library (
<filesystem>)- Description: Provides operations for manipulating paths, files, and directories.
- StreamFlix Example: Managing downloaded video files or cache directories.
#include <filesystem> // Standard header #include <iostream> #include <fstream> namespace fs = std::filesystem; int main() { fs::path appCacheDir = fs::temp_directory_path() / "StreamFlixCache"; try { if (!fs::exists(appCacheDir)) { if (fs::create_directories(appCacheDir)) { std::cout << "Created cache directory: " << appCacheDir << std::endl; } } else { std::cout << "Cache directory already exists: " << appCacheDir << std::endl; } fs::path downloadedMovie = appCacheDir / "inception.mp4"; // Simulate downloading a file std::ofstream(downloadedMovie) << "dummy video data"; if (fs::exists(downloadedMovie)) { std::cout << "Movie file size: " << fs::file_size(downloadedMovie) << " bytes." << std::endl; // fs::remove(downloadedMovie); // Clean up } } catch (const fs::filesystem_error& e) { std::cerr << "Filesystem error: " << e.what() << std::endl; std::cerr << "Path1: " << e.path1() << std::endl; if (!e.path2().empty()) std::cerr << "Path2: " << e.path2() << std::endl; } return 0; }
-
Template Argument Deduction for Class Templates (CTAD)
- Description: The compiler can deduce class template arguments from constructor arguments, similar to function template argument deduction.
- StreamFlix Example: Creating
std::pairor a custom templatedMediaItemwithout explicit template arguments.#include <vector> #include <string> #include <utility> // For std::pair #include <tuple> // For std::tuple #include <iostream> template<typename T1, typename T2> struct MediaPair { T1 first; T2 second; MediaPair(T1 f, T2 s) : first(f), second(s) {} void print() { std::cout << "MediaPair: (" << first << ", " << second << ")\n"; } }; // Deduction guide (often not needed for simple cases like above with C++17) // template<typename T1, typename T2> MediaPair(T1, T2) -> MediaPair<T1, T2>; int main() { // Before C++17 (or without CTAD) // std::pair<int, std::string> movieRatingOld(101, "Awesome"); // MediaPair<int, const char*> customPairOld(202, "TV Show"); // With C++17 CTAD std::pair movieRating(101, std::string("Awesome")); // Deduces std::pair<int, std::string> std::tuple userWatchHistory(123, "movie_abc", 1200); // Deduces std::tuple<int, const char*, int> MediaPair customPair(202, "TV Show"); // Deduces MediaPair<int, const char*> customPair.print(); std::cout << "Movie Rating ID: " << movieRating.first << ", Desc: " << movieRating.second << std::endl; return 0; }
-
[[nodiscard]]Attribute- Description: Encourages compilers to issue a warning if the return value of a function marked
[[nodiscard]]is ignored. - StreamFlix Example: A function that attempts to acquire a playback lock, whose result (success/failure) must be checked.
#include <iostream> // It's important to check if the lock was acquired [[nodiscard]] bool acquirePlaybackLock(int resourceId) { std::cout << "Attempting to acquire lock for resource: " << resourceId << std::endl; // Simulate lock acquisition logic if (resourceId % 2 == 0) { std::cout << "Lock acquired for " << resourceId << std::endl; return true; } std::cout << "Failed to acquire lock for " << resourceId << std::endl; return false; } void playContent(int contentId) { std::cout << "Playing content " << contentId << std::endl; } int main() { // acquirePlaybackLock(100); // Compiler warning: ignoring return value of function declared with 'nodiscard' attribute if (acquirePlaybackLock(100)) { // Good: result is used playContent(100); // releasePlaybackLock(100); } if (acquirePlaybackLock(101)) { playContent(101); // releasePlaybackLock(101); } else { std::cout << "Cannot play content 101, lock not acquired.\n"; } return 0; }
- Description: Encourages compilers to issue a warning if the return value of a function marked
-
Fold Expressions
- Description: A concise way to apply a binary operator over all arguments of a parameter pack in variadic templates.
- StreamFlix Example: Calculating the total duration of several video clips in a playlist.
#include <iostream> #include <string> // Unary right fold template<typename... Args> void printAllItems(Args... args) { // (std::cout << ... << args) << '\n'; // This doesn't work as expected directly // Correct way for printing is often a C-style array or initializer list trick pre-C++17 // or recursive template, or with C++17 fold: ((std::cout << args << " "), ...); // Prints "item1 item2 item3 " std::cout << std::endl; } // Binary left fold template<typename... Durations> int sumDurations(Durations... durations) { return (durations + ... + 0); // or (... + durations) for right fold. 0 for empty pack. } int main() { printAllItems("Clip1.mp4", "Ad_Break.mp4", "Clip2.mp4"); int totalPlaylistTimeSec = sumDurations(120, 30, 180); // 120s, 30s, 180s std::cout << "Total playlist duration: " << totalPlaylistTimeSec << " seconds." << std::endl; int emptyPlaylistTime = sumDurations(); std::cout << "Empty playlist duration: " << emptyPlaylistTime << " seconds." << std::endl; return 0; }
-
inlineVariables- Description: Allows defining static data members within a class definition in a header file (ODR-safe).
- StreamFlix Example: Defining a global default
StreamSettingsobject accessible across translation units.To make the above example runnable directly:// In a header file (e.g., stream_settings.h) #ifndef STREAM_SETTINGS_H #define STREAM_SETTINGS_H #include <string> #include <iostream> // For example struct StreamSettings { int defaultBitrateKbps = 2500; std::string defaultAudioCodec = "AAC"; // C++17 inline static data member inline static const StreamSettings GlobalDefaults; // Before C++17, you'd declare `static const StreamSettings GlobalDefaults;` here // and define it in one .cpp file: `const StreamSettings StreamSettings::GlobalDefaults;` void print() const { std::cout << "Bitrate: " << defaultBitrateKbps << ", Audio: " << defaultAudioCodec << std::endl; } }; #endif // STREAM_SETTINGS_H // In main.cpp (or any other .cpp file that includes stream_settings.h) // #include "stream_settings.h" // (assuming it's in a separate file) // int main() { // std::cout << "Global default stream settings:\n"; // StreamSettings::GlobalDefaults.print(); // StreamSettings customSettings; // customSettings.defaultBitrateKbps = 5000; // std::cout << "Custom settings:\n"; // customSettings.print(); // return 0; // }
#include <string> #include <iostream> // Content of stream_settings.h struct StreamSettings { int defaultBitrateKbps = 2500; std::string defaultAudioCodec = "AAC"; inline static const StreamSettings GlobalDefaults; // For non-const static members, or pre-C++17 const static members of non-integral/enum type: // inline static StreamSettings modifiableGlobalDefaults; // C++17 only void print() const { std::cout << "Bitrate: " << defaultBitrateKbps << "kbps, Audio Codec: " << defaultAudioCodec << std::endl; } }; // End of stream_settings.h content int main() { std::cout << "Global default stream settings from StreamFlix app:\n"; StreamSettings::GlobalDefaults.print(); StreamSettings userPreferredSettings; userPreferredSettings.defaultBitrateKbps = 8000; // User wants higher quality userPreferredSettings.defaultAudioCodec = "Opus"; std::cout << "User preferred settings for StreamFlix:\n"; userPreferredSettings.print(); return 0; }
-
[[fallthrough]],[[maybe_unused]]Attributes- Description:
[[fallthrough]]: Indicates intentional fall-through in aswitchstatement to suppress warnings.[[maybe_unused]]: Suppresses warnings about an unused entity (variable, parameter, etc.).
- StreamFlix Example: Handling different subscription tiers with fallthrough, and a parameter only used in debug builds.
#include <iostream> #include <string> enum class SubscriptionTier { Free, Basic, Premium, Ultra }; void configureFeatures(SubscriptionTier tier, [[maybe_unused]] bool enableDebugLogs) { // enableDebugLogs might only be used in #ifdef DEBUG blocks #ifdef DEBUG if (enableDebugLogs) std::cout << "Debug logs enabled for feature config.\n"; #endif std::cout << "Configuring features for tier: "; switch (tier) { case SubscriptionTier::Ultra: std::cout << "Ultra - Enabling 8K streaming, offline everything.\n"; [[fallthrough]]; // Ultra users get all Premium features too case SubscriptionTier::Premium: std::cout << "Premium - Enabling 4K streaming, multi-device, downloads.\n"; [[fallthrough]]; // Premium users get all Basic features case SubscriptionTier::Basic: std::cout << "Basic - Enabling HD streaming, single device.\n"; [[fallthrough]]; // Basic users get Free features (ads) case SubscriptionTier::Free: std::cout << "Free - Enabling SD streaming with ads.\n"; break; default: std::cout << "Unknown tier.\n"; } } int main() { configureFeatures(SubscriptionTier::Premium, true); std::cout << "\n"; configureFeatures(SubscriptionTier::Free, false); return 0; }
- Description:
This list covers many of the most prominent features. Each C++ standard also included numerous smaller library additions (e.g., new math functions, container member functions, utilities in <algorithm> and <numeric>) which are too many to list exhaustively here but contribute to the overall power and convenience of modern C++.