C++17 Features And STL Fixes In VS 2017 15.3

August 11th, 2017

Visual Studio 2017’s first toolset update, version 15.3, is currently in preview and will be released in its final form very soon. (The toolset consists of the compiler, linker, and libraries. After VS 2017 RTM, the 15.1 and 15.2 updates improved the IDE. The 15.3 update improves both the IDE and the toolset. In general, you should expect the IDE to be updated at a higher frequency than the toolset.)

As usual, we’ve maintained a detailed list of the STL fixes that are available in the 15.3 update. We also have newer feature tables for the STL and the compiler.

New Features (in addition to C++17 features):

* The STL no longer depends on Magic Statics, allowing clean use in code compiled with /Zc:threadSafeInit-.

* Implemented P0602R0 “variant and optional should propagate copy/move triviality”.

* The STL now officially tolerates dynamic RTTI being disabled via /GR-. dynamic_pointer_cast() and rethrow_if_nested() inherently require dynamic_cast, so the STL now marks them as =delete under /GR-.

* Even when dynamic RTTI has been disabled via /GR-, “static RTTI” (in the form of typeid(SomeType)) is still available and powers several STL components. The STL now supports disabling this too, via /D_HAS_STATIC_RTTI=0. Note that this will disable std::any, std::function’s target() and target_type(), and shared_ptr’s get_deleter().

Correctness Fixes:

* STL containers now clamp their max_size() to numeric_limits<difference_type>::max() rather than size_type’s max. This ensures that the result of distance() on iterators from that container is representable in the return type of distance().

* Fixed missing specialization auto_ptr<void>.

* The meow_n() algorithms previously failed to compile if the length argument was not an integral type; they now attempt to convert non-integral lengths to the iterators’ difference_type.

* normal_distribution<float> no longer emits warnings inside the STL about narrowing from double to float.

* Fixed some basic_string operations which were comparing with npos instead of max_size() when checking for maximum size overflow.

* condition_variable::wait_for(lock, relative_time, predicate) would wait for the entire relative time in the event of a spurious wake. Now, it will wait for only a single interval of the relative time.

* future::get() now invalidates the future, as the standard requires.

* iterator_traits<void *> used to be a hard error because it attempted to form void&; it now cleanly becomes an empty struct to allow use of iterator_traits in “is iterator” SFINAE conditions.

* Some warnings reported by Clang -Wsystem-headers were fixed.

* Also fixed “exception specification in declaration does not match previous declaration” reported by Clang -Wmicrosoft-exception-spec.

* Also fixed mem-initializer-list ordering warnings reported by Clang and C1XX.

* The unordered containers did not swap their hashers or predicates when the containers themselves were swapped. Now they do.

* Many container swap operations are now marked noexcept (as our STL never intends to throw an exception when detecting the non-propagate_on_container_swap non-equal-allocator undefined behavior condition).

* Many vector<bool> operations are now marked noexcept.

* The STL will now enforce matching allocator value_types (in C++17 mode) with an opt-out escape hatch.

* Fixed some conditions where self-range-insert into basic_strings would scramble the strings’ contents. (Note: self-range-insert into vectors is still prohibited by the Standard.)

* basic_string::shrink_to_fit() is no longer affected by the allocator’s propagate_on_container_swap.

* std::decay now handles abominable function types (i.e. function types that are cv-qualified and/or ref-qualified).

* Changed include directives to use proper case sensitivity and forward slashes, improving portability.

* Fixed warning C4061 “enumerator ‘Meow’ in switch of enum ‘Kitten’ is not explicitly handled by a case label”. This warning is off-by-default and was fixed as an exception to the STL’s general policy for warnings. (The STL is /W4 clean, but does not attempt to be /Wall clean. Many off-by-default warnings are extremely noisy and aren’t intended to be used on a regular basis.)

* Improved std::list’s debug checks. List iterators now check operator->(), and list::unique() now marks iterators as invalidated.

* Fixed uses-allocator metaprogramming in tuple.

Performance/Throughput Fixes:

* Worked around interactions with noexcept which prevented inlining std::atomic’s implementation into functions that use Structured Exception Handling (SEH).

* Changed the STL’s internal _Deallocate() function to optimize into smaller code, allowing it to be inlined into more places.

* Changed std::try_lock() to use pack expansion instead of recursion.

* Improved std::lock()’s deadlock avoidance algorithm to use lock() operations instead of spinning on all the locks’ try_lock()s.

* Enabled the Named Return Value Optimization in system_category::message().

* conjunction and disjunction now instantiate N + 1 types, instead of 2N + 2 types.

* std::function no longer instantiates allocator support machinery for each type-erased callable, improving throughput and reducing .obj size in programs that pass many distinct lambdas to std::function.

* allocator_traits<std::allocator> contains manually inlined std::allocator operations, reducing code size in code that interacts with std::allocator through allocator_traits only (i.e. most code).

* The C++11 minimal allocator interface is now handled by the STL calling allocator_traits directly, instead of wrapping the allocator in an internal class _Wrap_alloc. This reduces the code size generated for allocator support, improves the optimizer’s ability to reason about STL containers in some cases, and provides a better debugging experience (as now you see your allocator type, rather than _Wrap_alloc<your allocator type> in the debugger).

* Removed metaprogramming for customized allocator::reference, which allocators aren’t actually allowed to customize. (Allocators can make containers use fancy pointers but not fancy references.)

* The compiler front-end was taught to unwrap debug iterators in range-based for-loops, improving the performance of debug builds.

* basic_string’s internal shrink path for shrink_to_fit() and reserve() is no longer in the path of reallocating operations, reducing code size for all mutating members.

* basic_string’s internal grow path is no longer in the path of shrink_to_fit().

* basic_string’s mutating operations are now factored into non-allocating fast path and allocating slow path functions, making it more likely for the common no-reallocate case to be inlined into callers.

* basic_string’s mutating operations now construct reallocated buffers in the desired state rather than resizing in place. For example, inserting at the beginning of a string now moves the content after the insertion exactly once (either down or to the newly allocated buffer), instead of twice in the reallocating case (to the newly allocated buffer and then down).

* Operations calling the C standard library in <string> now cache errno’s address to remove repeated interaction with TLS.

* Simplified is_pointer’s implementation.

* Finished changing function-based Expression SFINAE to struct/void_t-based.

* STL algorithms now avoid postincrementing iterators.

* Fixed truncation warnings when using 32-bit allocators on 64-bit systems.

* std::vector move assignment is now more efficient in the non-POCMA non-equal-allocator case, by reusing the buffer when possible.

Readability And Other Improvements:

* The STL now uses C++14 constexpr unconditionally, instead of conditionally-defined macros.

* The STL now uses alias templates internally.

* The STL now uses nullptr internally, instead of nullptr_t{}. (Internal usage of NULL has been eradicated. Internal usage of 0-as-null is being cleaned up gradually.)

* The STL now uses std::move() internally, instead of stylistically misusing std::forward().

* Changed static_assert(false, “message”) to #error message. This improves compiler diagnostics because #error immediately stops compilation.

* The STL no longer marks functions as __declspec(dllimport). Modern linker technology no longer requires this.

* Extracted SFINAE to default template arguments, which reduces clutter compared to return types and function argument types.

* Debug checks in <random> now use the STL’s usual machinery, instead of the internal function _Rng_abort() which called fputs() to stderr. This function’s implementation is being retained for binary compatibility, but has been removed in the next binary-incompatible version of the STL.

STL Feature Status:

We’re going to continue to add new features to VS 2017 in toolset updates, and we’re working on the second toolset update right now. While we can’t reveal its version number or provide an ETA, we can show you which features have already been implemented (and this list will continue to grow). For now, we’ll refer to the second toolset update as “VS 2017 15.x” (please don’t try to guess what x is, you’ll just create confusion).

Status Std Paper Title Notes missing C++20 P0463R1 endian missing C++20 P0674R1 make_shared() For Arrays missing C++17 P0433R2 Deduction Guides For The STL patch C++17 P0739R0 Improving Class Template Argument Deduction For The STL [DR] missing C++17 P0607R0 Inline Variables For The STL (Options A and B2) missing C++17 P0426R1 constexpr For char_traits missing C++17 P0083R3 Splicing Maps And Sets patch C++17 P0508R0 Clarifying insert_return_type missing C++17 P0067R5 Elementary String Conversions patch C++17 P0682R1 Repairing Elementary String Conversions [DR] … C++17 P0220R1 Library Fundamentals V1 missing C++17 … <memory_resource> patch C++17 P0337R0 Deleting polymorphic_allocator Assignment missing C++17 P0030R1 hypot(x, y, z) missing C++17 P0226R1 Mathematical Special Functions missing C++17 P0024R2 Parallel Algorithms [parallel] patch C++17 P0336R1 Renaming Parallel Execution Policies patch C++17 P0394R4 Parallel Algorithms Should terminate() For Exceptions patch C++17 P0452R1 Unifying <numeric> Parallel Algorithms patch C++17 P0467R2 Requiring Forward Iterators In Parallel Algorithms patch C++17 P0502R0 Parallel Algorithms Should terminate() For Exceptions, Usually patch C++17 P0518R1 Copying Trivially Copy Constructible Elements In Parallel Algorithms patch C++17 P0523R1 Relaxing Complexity Requirements Of Parallel Algorithms (General) patch C++17 P0574R1 Relaxing Complexity Requirements Of Parallel Algorithms (Specific) patch C++17 P0623R0 Final C++17 Parallel Algorithms Fixes missing C++17 P0218R1 <filesystem> patch C++17 P0219R1 Relative Paths For Filesystem patch C++17 P0317R1 Directory Entry Caching For Filesystem patch C++17 P0392R0 Supporting string_view In Filesystem Paths patch C++17 P0430R2 Supporting Non-POSIX Filesystems patch C++17 P0492R2 Resolving NB Comments For Filesystem VS 2017 15.x C++17 P0003R5 Removing Dynamic Exception Specifications [rem] VS 2017 15.x C++17 P0005R4 not_fn() VS 2017 15.x C++17 P0033R1 Rewording enable_shared_from_this [14] VS 2017 15.x C++17 P0174R2 Deprecating Vestigial Library Parts [depr] VS 2017 15.x C++17 P0302R1 Removing Allocator Support In std::function [rem] VS 2017 15.x C++17 P0358R1 Fixes For not_fn() VS 2017 15.x C++17 P0414R2 shared_ptr<T[]>, shared_ptr<T[N]> [14] VS 2017 15.x C++17 P0497R0 Fixing shared_ptr For Arrays [14] VS 2017 15.x C++17 P0521R0 Deprecating shared_ptr::unique() [depr] VS 2017 15.x C++17 P0618R0 Deprecating <codecvt> [depr] VS 2017 15.3 C++17 … Boyer-Moore search() VS 2017 15.3 C++17 P0031R0 constexpr For <array> (Again) And <iterator> VS 2017 15.3 C++17 P0040R3 Extending Memory Management Tools VS 2017 15.3 C++17 P0084R2 Emplace Return Type VS 2017 15.3 C++17 P0152R1 atomic::is_always_lock_free VS 2017 15.3 C++17 P0154R1 hardware_destructive_interference_size, etc. VS 2017 15.3 C++17 P0156R2 scoped_lock VS 2017 15.3 C++17 P0253R1 Fixing Searcher Return Types VS 2017 15.3 C++17 P0258R2 has_unique_object_representations [obj_rep] VS 2017 15.3 C++17 P0295R0 gcd(), lcm() VS 2017 15.3 C++17 P0298R3 std::byte [byte] VS 2017 15.3 C++17 P0403R1 UDLs For <string_view> (“meow”sv, etc.) VS 2017 15.3 C++17 P0418R2 atomic compare_exchange memory_order Requirements [14] VS 2017 15.3 C++17 P0435R1 Overhauling common_type [14] VS 2017 15.3 C++17 P0505R0 constexpr For <chrono> (Again) VS 2017 15.3 C++17 P0513R0 Poisoning hash [14] VS 2017 15.3 C++17 P0516R0 Marking shared_future Copying As noexcept [14] VS 2017 15.3 C++17 P0517R0 Constructing future_error From future_errc [14] VS 2017 15.3 C++17 P0548R1 Tweaking common_type And duration [14] VS 2017 15.3 C++17 P0558R1 Resolving atomic<T> Named Base Class Inconsistencies [atomic] [14] VS 2017 15.3 C++17 P0599R1 noexcept hash [14] VS 2017 15.3 C++17 P0604R0 invoke_result, is_invocable, is_nothrow_invocable [depr] VS 2017 C++17 … <algorithm> sample() VS 2017 C++17 … <any> VS 2017 C++17 … <optional> VS 2017 C++17 … <string_view> VS 2017 C++17 … <tuple> apply() VS 2017 C++17 P0032R3 Homogeneous Interface For variant/any/optional VS 2017 C++17 P0077R2 is_callable, is_nothrow_callable VS 2017 C++17 P0088R3 <variant> VS 2017 C++17 P0163R0 shared_ptr::weak_type VS 2017 C++17 P0209R2 make_from_tuple() VS 2017 C++17 P0254R2 Integrating string_view And std::string VS 2017 C++17 P0307R2 Making Optional Greater Equal Again VS 2017 C++17 P0393R3 Making Variant Greater Equal VS 2017 C++17 P0504R0 Revisiting in_place_t/in_place_type_t<T>/in_place_index_t<I> VS 2017 C++17 P0510R0 Rejecting variants Of Nothing, Arrays, References, And Incomplete Types VS 2015.3 C++17 P0025R1 clamp() VS 2015.3 C++17 P0185R1 is_swappable, is_nothrow_swappable VS 2015.3 C++17 P0272R1 Non-const basic_string::data() VS 2015.2 C++17 N4387 Improving pair And tuple [14] VS 2015.2 C++17 N4508 shared_mutex (Untimed) [14] VS 2015.2 C++17 P0004R1 Removing Deprecated Iostreams Aliases [rem] VS 2015.2 C++17 P0006R0 Variable Templates For Type Traits (is_same_v, etc.) [14] VS 2015.2 C++17 P0007R1 as_const() [14] VS 2015.2 C++17 P0013R1 Logical Operator Type Traits (conjunction, etc.) [14] VS 2015.2 C++17 P0074R0 owner_less<> [14] VS 2015.2 C++17 P0092R1 <chrono> floor(), ceil(), round(), abs() [14] VS 2015.2 C++17 P0156R0 Variadic lock_guard [14] VS 2015 C++17 N3911 void_t [14] VS 2015 C++17 N4089 Safe Conversions In unique_ptr<T[]> [14] VS 2015 C++17 N4169 invoke() [14] VS 2015 C++17 N4190 Removing auto_ptr, random_shuffle(), And Old <functional> Stuff [rem] VS 2015 C++17 N4258 noexcept Cleanups [14] VS 2015 C++17 N4259 uncaught_exceptions() [14] VS 2015 C++17 N4277 Trivially Copyable reference_wrapper [14] VS 2015 C++17 N4279 insert_or_assign()/try_emplace() For map/unordered_map [14] VS 2015 C++17 N4280 size(), empty(), data() [14] VS 2015 C++17 N4366 Precisely Constraining unique_ptr Assignment [14] VS 2015 C++17 N4389 bool_constant [14] VS 2015 C++17 P0063R3 C11 Standard Library [C11] [14] VS 2013 C++17 N4510 Supporting Incomplete Types In vector/list/forward_list [14]

For clarity, the Library Fundamentals V1 paper has been decomposed into its individual features, marked by “…” here.

To give you a better idea of our status, unimplemented papers are marked “missing” for primary features, or “patch” for papers that merely fixed parts of a primary feature. We implement them together, so the large number of “patch” rows doesn’t really indicate a large amount of missing work.

[DR] These papers were voted into the Working Paper after C++17, but as Defect Reports, meaning that they retroactively apply to C++17 (as bugfixes).

[parallel] The Parallel Algorithms are being gradually implemented. Some are available, but we’re still working on them.

[rem] Feature removals are activated by /std:c++17 (or /std:c++latest), with opt-out macros. The macros are _HAS_AUTO_PTR_ETC, _HAS_FUNCTION_ALLOCATOR_SUPPORT, _HAS_OLD_IOSTREAMS_MEMBERS, and _HAS_UNEXPECTED.

[14] These C++17 features are implemented unconditionally, even in /std:c++14 mode (the default). For some features, this was because they predated the introduction of MSVC’s Standard mode options. For other features, conditional implementation would be nearly pointless or undesirably complicated.

[depr] VS 2017 15.x (the second toolset update) will warn about usage of all STL features that were deprecated in C++17 (with the exception of the <stdio.h> family of C headers). /std:c++14 will not emit these warnings, but /std:c++17 (and /std:c++latest) will. The warning messages will be highly detailed, and will mention both the coarse-grained and fine-grained escape hatch macros. In particular, note that while invoke_result was implemented in 15.3, result_of deprecation will appear in 15.x.

[obj_rep] has_unique_object_representations is powered by a compiler intrinsic. Although this has been implemented in EDG (powering Intellisense), we haven’t activated it for that compiler yet. Also, the intrinsic is not yet available in Clang at all.

[byte] std::byte is enabled by /std:c++17 (and /std:c++latest), but has a fine-grained opt-out macro (_HAS_STD_BYTE can be defined to be 0). This is because given certain patterns of using-directives, it can conflict with the Windows SDK’s headers. This has been reported to the SDK team and will be fixed, but in the meantime the escape hatch is available.

[atomic] This is almost completely implemented in VS 2017 15.3, and the remaining differences are difficult to observe (some signatures differ from the Standard, as observed by taking their address or providing explicit template arguments). The STL’s next major binary-incompatible version will fix the remaining differences.

[C11] First available in VS 2015, the Universal CRT implemented the parts of the C11 Standard Library that are required by C++17, with minor exceptions. Those exceptions (which are tracked by bugs) are: missing C99 strftime() E/O alternative conversion specifiers, missing C11 fopen() exclusive mode, and missing C11 aligned_alloc(). The strftime() and fopen() functionality will be implemented in the future. aligned_alloc() will probably never be implemented, as C11 specified it in a way that’s incompatible with our implementation (namely, that free() must be able to handle highly aligned allocations).

For clarity, this table has omitted a number of papers that are Not Applicable (nothing for implementers to do, or users to take advantage of), such as wording clarifications.

Finally, note that this table contains one change relative to VS 2017 15.3 Preview 2 – we implemented P0604R0 “invoke_result, is_invocable, is_nothrow_invocable”, permanently renaming P0077R2 “is_callable, is_nothrow_callable”.

Compiler Feature Status:

C++03/11 Core Language Features Status Paper Notes [Everything else] VS 2015 [A] Two-phase name lookup Partial [B] Expression SFINAE Partial N2634 [C] C99 preprocessor Partial N1653 [D] Extended integer types N/A N1988 [E] C++14 Core Language Features Status Paper Notes Tweaked wording for contextual conversions VS 2013 N3323 Binary literals VS 2015 N3472 auto and decltype(auto) return types VS 2015 N3638 init-captures VS 2015 N3648 Generic lambdas VS 2015 N3649 [[deprecated]] attribute VS 2015 N3760 Sized deallocation VS 2015 N3778 Digit separators VS 2015 N3781 Variable templates VS 2015.2 N3651 Extended constexpr VS 2017 N3652 NSDMIs for aggregates VS 2017 N3653 Avoiding/fusing allocations N/A N3664 [F] C++17 Core Language Features Status Paper Notes Removing trigraphs VS 2010 N4086 [14] New rules for auto with braced-init-lists VS 2015 N3922 [14] typename in template template-parameters VS 2015 N4051 [14] Attributes for namespaces and enumerators VS 2015 N4266 [14] u8 character literals VS 2015 N4267 [14] Nested namespace definitions VS 2015.3 N4230 Terse static_assert VS 2017 N3928 Generalized range-based for-loops VS 2017 P0184R0 [14] [[fallthrough]] attribute VS 2017 P0188R1 Removing the register keyword VS 2017 15.3 P0001R1 Removing operator++ for bool VS 2017 15.3 P0002R1 Capturing *this by value VS 2017 15.3 P0018R3 Using attribute namespaces without repetition VS 2017 15.3 P0028R4 __has_include VS 2017 15.3 P0061R1 [14] Direct-list-init of fixed enums from integers VS 2017 15.3 P0138R2 constexpr lambdas VS 2017 15.3 P0170R1 [[nodiscard]] attribute VS 2017 15.3 P0189R1 [[maybe_unused]] attribute VS 2017 15.3 P0212R1 Structured bindings VS 2017 15.3 P0217R3 constexpr if-statements VS 2017 15.3 P0292R2 [G] Selection statements with initializers VS 2017 15.3 P0305R1 Hexfloat literals VS 2017 15.x P0245R1 Matching template template-parameters to compatible arguments VS 2017 15.x P0522R0 Fixing qualification conversions No N4261 Allowing more non-type template args No N4268 Fold expressions No N4295 Removing dynamic-exception-specifications No P0003R5 Adding noexcept to the type system No P0012R1 Extended aggregate initialization No P0017R1 Over-aligned dynamic memory allocation No P0035R4 Removing some empty unary folds No P0036R0 Template argument deduction for class templates No P0091R3 and P0512R0 Declaring non-type template parameters with auto No P0127R2 Guaranteed copy elision No P0135R1 [H] Rewording inheriting constructors No P0136R1 Refining expression evaluation order No P0145R3 and P0400R0 Pack expansions in using-declarations No P0195R2 Ignoring unrecognized attributes No P0283R2 Inline variables No P0386R2 Fixing class template argument deduction for initializer-list ctors No P0702R1 [DR] C++20 Core Language Features Status Paper Notes Adding __VA_OPT__ for comma omission and comma deletion No P0306R4 Designated initialization No P0329R4 Allowing lambda-capture [=, this] No P0409R2 Familiar template syntax for generic lambdas No P0428R2 Default member initializers for bit-fields No P0683R1 Fixing const lvalue ref-qualified pointers to members No P0704R1 Concepts No P0734R0

[A] While dynamic exception specifications remain unimplemented, they were mostly removed in C++17 by P0003R5. One vestige remains in C++17, where throw() is deprecated and required to behave as a synonym for noexcept(true). MSVC doesn’t implement that behavior for throw() (it is still treated as a synonym for __declspec(nothrow)), but you can simply avoid throw() and use noexcept instead.

[B] Two-phase name lookup is partially implemented in VS 2017 15.3, and a detailed blog post will be available very soon.

[C] Expression SFINAE is partially implemented in VS 2017 15.3. While many scenarios work (and it has been sufficiently solid for the STL’s purposes for quite a while), some parts are still missing and some workarounds are still required.

[D] Support for C99’s preprocessor rules is unchanged (considered partial due to support for variadic macros, although there are numerous bugs). The preprocessor will be overhauled as part of finishing C++17.

[E] Extended Integer Types are marked as Not Applicable because implementations are permitted, but not required, to provide such types. Like GCC and Clang, MSVC has chosen to not provide extended integer types.

[F] Similarly, the rules for avoiding/fusing allocations are marked as Not Applicable because this is an optimization that is permitted, but not required. We currently have no plans to implement this (as reports indicate that it isn’t an especially valuable optimization).

[14] Unconditionally available, even in /std:c++14 mode.

[G] “if constexpr” is supported in /std:c++14 with a warning that can be suppressed, delighting template metaprogramming library authors everywhere.

[H] Unfortunately, while Guaranteed Copy Elision was implemented in preview builds of VS 2017 15.3, it had to be reverted due to bugs that were discovered. These bugs will be fixed before the feature is restored.

[DR] Like the STL, the Core Language also had a paper that was voted in as a Defect Report, retroactively applying to C++17. Time is no obstacle to the C++ Standardization Committee.

Reporting Bugs

Please let us know what you think about VS 2017 15.3. You can use the IDE’s Report A Problem to report bugs. For compiler and library bugs, it’s important to provide self-contained test cases.

Billy Robert O’Neal III @MalwareMinigun bion@microsoft.com

Casey Carter @CoderCasey cacarter@microsoft.com

Stephan T. Lavavej @StephanTLavavej stl@microsoft.com

Steve Wishnousky stwish@microsoft.com