This is an interesting question, with not an easy answer.
I would say that the correct answer is: “It depends.”
Modern C++ started with C++11. I think C++11 is the most impactful version of C++ to date, as it introduced very important and convenient features like: range-for loops, lambdas, move semantics, standard smart pointers like std::unique_ptr and std::shared_ptr, etc.
C++14 was kind of a small improvement for things that didn’t make it into C++11. For example, C++11 had std::make_shared for std::shared_ptr, but it clearly lacked the corresponding std::make_unique for std::unique_ptr. Well, std::make_unique (and other small features, like supporting auto in lambda parameters) were added in C++14.
Then it came C++17. Again, no big new features here, at least not at the C++11 impact level, but some convenient stuff, like: attributes (e.g. [[nodiscard]], [[fallthrough]], or [[maybe_unused]]); static_assert with no messages (a.k.a. terse static_assert); structured bindings, which come in handy in some cases like when iterating through containers like std::map; new standard library components like std::variant, etc.
Some library features that were previously deprecated were definitively removed in C++17; so that could break some existing legacy C++ code that previously compiled just fine in your projects.
And this brings an important point when picking the C++ version for your codebase: Does using C++ version X > Y break existing code? Is it compatible with older legacy libraries that you don’t want to or cannot upgrade or fix? Does it break some binary compatibility interface (ABI)1? Is it supported by your toolchain(s)?
For example, if you want to target Windows XP with Microsoft Visual C++ compiler, the latest toolset that has Windows XP support is v141_xp, which is a toolset from Visual Studio 20172, having full C++14 support, and partial C++17 support (for example, you can use features like terse static_assert and std::variant from C++17, but not other features like std::shared_mutex).3
In general, I would say that these days targeting C++17 is fine, and if your toolset supports C++20, and if it doesn’t break any existing library or legacy component you depend on (and you don’t want to/are unable to fix), then C++20 can be a good choice, too.
Keep in mind that today in 2026 (August 18th, 2026), Google’s C++ Style Guide still targets C++204, and LLVM C++17.


Note also that targeting a given C++ version, like C++20, does not mean that you have to use all the features available in that language version!
For example, talking about the C++20 adoption by Google’s C++ Style Guide, it’s worth noting that, the main “Big Three Features” of C++20, i.e. concepts, modules, and coroutines, are used sparingly, or not used at all!
For example, on concepts:
Use concepts sparingly.
And on coroutines:
Use only coroutine libraries that have been approved for project-wide use by your project leads. Do not roll your own promise or awaitable types.
Moreover, on C++20 modules:
Do not use C++20 Modules.
Remember that, at the end of the day, the key is to write code that is clear, easy to read, understand and maintain, and not some mess of esotheric advanced features that make it impossible or very hard to understand what’s going on, or unstable features not well supported by the available toolsets.
- See for example the C++20 [[no_unique_address]] problem with MSVC. ↩︎
- It comes with Visual Studio 2019, too. ↩︎
- You can read more about that in this StackOverflow answer. ↩︎
- Despite reading: “The C++ version targeted by this guide will advance (aggressively) over time.” (emphasis mine), they are not even targeting C++23 in (at least mid August) 2026. ↩︎











