STL Fixes In VS 2015 Update 2

In addition to 10 new features (and 16 Library Issue resolutions), the STL in VS 2015 Update 2 contains numerous improvements for correctness and performance. (Previous bugfix changelogs: RTM Part 1, RTM Part 2, and Update 1. We also have a list of compiler and IDE fixes in Update 2.) These STL fixes were implemented by Billy O’Neal (@MalwareMinigun), Steve Wishnousky, James McNellis (@JamesMcNellis), and myself (@StephanTLavavej).

The Iostreams Floating-Point Performance/Correctness Fix

In Update 2, as measured on my machine, “stream >> dbl” is 19.5x faster, and “stream >> flt” is 17.0x faster. Yes, that’s TIMES, not percent. This completely reverses (and then some!) the performance regression that was introduced between VS 2010 and 2012, and was worsened between 2013 and 2015. Additionally, every written bit is correct, verified by round-tripping all finite 32-bit floats, plus a regression test for tricky 64-bit doubles. This fixes many bug reports (VSO#103391/Connect#1540816, VSO#115506/Connect#1601079, VSO#120754/Connect#1311640, VSO#181316/Connect#2245376, and many more duplicates). I figured out how to fix this in Update 2 while preserving binary compatibility. The next major version of the libraries will contain a more comprehensive version of this fix, where I was able to delete 31 source files and shrink the STL’s DLL by 12 KB.

Here are my performance measurements. I tested a million 32-bit floats and a million 64-bit doubles, avoiding memory allocations and averaging 10 runs. I compared iostreams to the CRT’s strtof()/strtod():


CRT float

STL float

CRT double

STL double

VS 2010

362.8 ms

930.1 ms

362.4 ms

929.7 ms

VS 2012

329.0 ms

6699.2 ms

329.0 ms

7939.3 ms

VS 2013

324.2 ms

6510.5 ms

337.2 ms

7972.7 ms

VS 2015.1

214.7 ms

12728.2 ms

247.4 ms

15244.5 ms

VS 2015.2

215.7 ms

747.7 ms

251.2 ms

780.2 ms

Yes, although iostreams are faster than ever before, they’re still slower than the CRT. This is expected, although we may be able to improve iostreams somewhat more in the future.

As for correctness, here are the results for round-tripping all finite 32-bit floats. That’s float ==> string ==> float, excluding INF/NAN, testing both decimal and hex:



VS 2013


VS 2015.1


VS 2015.2


Major Performance Fixes

* For many years, the STL has contained an optimization to call memmove() when possible, which can be faster than the Core Language. This is enabled by metaprogramming, and applies to vector reallocation, copy(), and other places. In Update 2, this optimization is significantly more aggressive, and when it activates, code can be up to 9.5x faster (VSO#179897, VSO#180469). The optimization inherently requires iterators to be pointers after “unwrapping” (so vector/array/string iterators are also eligible). To activate the optimization, our requirements for the pointed-to element types have changed. Previously, we required them to be identical scalar types (ignoring constness, so copying from const int to int was eligible). The Standard defines scalar types to be (possibly cv-qualified) arithmetic, enumeration, pointer, pointer-to-member, and nullptr_t. (We actually had a bug here, because we’d attempt to activate the optimization for copying from volatile int to volatile int, and then memmove() would fail to compile. But nobody complained for over a decade! That’s how obscure volatile is.) We had one extra trick: copying from X * elements to const X * elements can be performed via memmove() – although they’re different scalar types, we know that their representations are identical.

Importantly, user-defined types aren’t scalars, so they were never eligible for the optimization, even if they were as simple as a struct containing two ints. In Update 2, Billy overhauled this logic, extending it to trivially copyable types, even if they’re user-defined. We spent a lot of time thinking through the new metaprogramming, which is extremely aggressive while preserving complete correctness. The new criteria are: as usual, the iterators must be pointers after unwrapping. For the elements, we ignore constness but reject volatility. (Note that we’re careful about how we ignore constness – copying from int to const int won’t compile.) When the element types are the same, we rely on the is_trivially_copyable type trait, which recognizes UDTs that are safe to memmove(). When the element types are different, we’ve kept our “X * to const X *” special case, and added more. Now we’ll unwrap enums to their underlying integral types, and we’ll ask, “are these integral types, of the same size, that are both bool or both non-bool”. This means that we’ll activate memmove() for copying from int to unsigned int, but not from short to int. (We also ask is_trivially_assignable, to be extra sure that we aren’t going to bypass a user-defined assignment operator. Note, however, that is_trivially_assignable wouldn’t be sufficient all by itself. Assigning short to int is a “trivial” operation, but it can’t be accomplished via memmove(), because the element sizes are different.) Finally, when activating the memmove() optimization, the codegen size is slightly smaller.

TLDR: vector and copy() are faster, yay. And all you need to do is install Update 2 and recompile.

* <string>: to_string(integer) is up to 11x faster (VSO#153106).

* <string>: string::replace() is enormously faster when replacing same-size substrings (VSO#174871/Connect#2155092).

* <string>: string::push_back() is up to 3x faster (VSO#116522/Connect#1263155).

* <regex>: sub_match comparisons are faster, as they avoid constructing temporary std::strings (VSO#177524).

Minor Performance Fixes

* <functional>: I slightly improved the runtime efficiency and codegen size of copying std::functions. Very slightly.

* <algorithm>, <memory>: fill()/fill_n()/uninitialized_fill()/uninitialized_fill_n() are slightly more aggressive about calling memset().

* <vector>: vector’s ctor(N) and resize(N) are significantly more aggressive about calling memset() for all-bits-zero types.

* <string>: basic_string::compare(const basic_string&) had suboptimal codegen due to a backend bug/limitation affecting its noexcept marking (VSO#187864). The library now avoids this problem, while the backend will be improved in the future.

* <complex>: I slightly improved codegen by using <limits> for infinity()/quiet_NaN(), which (beginning in Update 1) are now powered by header-only compiler hooks.

Filesystem Fixes

* <experimental/filesystem>: canonical() mishandled paths like “../../meow” (VSO#121275/Connect#1629169, VSO#144257/Connect#1760162).

* <experimental/filesystem>: recursive_directory_iterator::disable_recursion_pending() permanently affected the iterator, but the TS says that it should affect the next increment only (VSO#171729).

* <experimental/filesystem>: equivalent(), hard_link_count(), and last_write_time() failed for directories (VSO#121387/Connect#1631910).

* <experimental/filesystem>: copy() didn’t follow the TS’s specification in several ways (VSO#153113).

Regex Fixes

* <regex>: Certain patterns of nested quantifiers triggered infinite loops when performing matches (VSO#91764, VSO#167760).

* <regex>: Constructing a regex from an invalid pattern would crash, when that pattern involved a character class abruptly ending with a backslash (VSO#159685/Connect#1961300). Now, regex(R”([\)”) throws error_escape as required by the Standard.

* <regex>: Despite fixes in previous major versions, regex still crashed with certain patterns containing high-bit non-ASCII characters (VSO#153556/Connect#1852540, VSO#178495/Connect#2218322). We believe that this has been fixed, once and for all.

* <regex>: We rejected attempts to escape non-special characters, like regex(R”(\z)”), by throwing regex_error (VSO#101318). Surprisingly, the Standard is unclear on whether this is valid. The C++ Standard refers to the ECMAScript 3 standard, which is full of confusing nonsense. I wish I were joking, but this is completely serious – its specification for IdentityEscape is totally unimplementable. ECMAScript 6 is equally affected, except that it has a normative Annex B “Additional ECMAScript Features for Web Browsers”, which specifies something reasonable (namely, that every non-special character can be escaped, except for the letter ‘c’). After surveying the behavior of various STL and browser implementations, where Boost, libstdc++, Microsoft Edge, and Google Chrome all accepted \z as an IdentityEscape, and libc++ was the only other library rejecting it, Billy changed our implementation to follow ES6 Annex B and accept this (which seems to be intuitive, reasonable behavior). He also filed LWG 2584, with a Proposed Resolution to unambiguously patch this in the C++ Standard.

Functional-ish Fixes

* <functional>: Through Microsoft Connect and the IDE’s Send-A-Smile, users reported bugs in std::function’s implicit conversions (VSO#95177, VSO#108113/Connect#1188553). These bugs were resolved when I implemented C++14’s std::function SFINAE. (Yes, I’m going to shamelessly double-count features and bugfixes.)

* <type_traits>: Users also submitted bug reports about result_of::type’s refusal to vanish (VSO#105317/Connect#1548688, VSO#120635). Resolved by C++14 result_of SFINAE.

* <functional>: Cranking up C4100 to level 3 (or more urgent) triggered an “unreferenced formal parameter” warning in my implementation of bind(), which was otherwise crystalline perfection (VSO#177244/Connect#2209399). This is not actually a supported scenario – the STL attempts to be /W4 /analyze clean (and is extensively tested accordingly), as long as the levels of warnings aren’t changed. However, this was a clear oversight, so I fixed it by removing the name. (I actually fixed this throughout the STL, which required a workaround for a compiler limitation with variadic templates).

* <type_traits>: is_function didn’t recognize “weird” function types (VSO#152213/Connect#1882163). These bizarre things are produced by decomposing cv/ref-qualified PMF types (if you don’t know what those are, you don’t want to know). They’re additionally strange because it’s impossible to form references to them (like cv void), or pointers to them (unlike cv void). I fixed up the STL to handle these things, implementing C++14 LWG 2196 “Specification of is_*[copy/move]_[constructible/assignable] unclear for non-referencable types” and C++17 LWG 2101 “Some transformation types can produce impossible types”.

Random Fixes

* <random>: shuffle_order_engine::seed() (including knuth_b::seed()) misbehaved at runtime (VSO#95604). Now they behave correctly.

* <random>: xor_combine has been removed. This was a TR1-only class which was intentionally omitted from the Standard.

Multithreading Fixes

* <thread>, <condition_variable>, etc.: Floating durations like 1.5s triggered compiler errors in this_thread::sleep_for(), condition_variable::wait_for(), etc. (VSO#122248/Connect#1636961, VSO#106920/Connect#1179590, VSO#153606/Connect#1839243)

* <thread>: this_thread::sleep_until() misbehaved at runtime for custom clocks with non-1970 epochs (VSO#99350, VSO#123833, VSO#144114/Connect#1743217). This included steady_clock/high_resolution_clock which has a varying epoch.

* <future>: After I implemented result_of SFINAE, Billy overhauled async()’s signatures to follow the Standard (VSO#97632). This fixed certain compiler errors when calling async().

* <future>: async() was incorrectly implemented with bind(), resulting in compiler errors for movable-only types (VSO#112570/Connect#1582910, VSO#111640). async() also shouldn’t have been activating bind()’s special treatment of types like placeholders (VSO#115515).

* <future>: promise<T> handled this correctly, but destroying promise<T&>/promise<void> before setting a value wouldn’t store a broken_promise exception (VSO#152487/Connect#1877917). I fixed this broken broken_promise promise by copy-pasting code, carefully.

* <atomic>: I fixed a subtle-but-nasty silent bad codegen bug affecting atomic<UDT> (VSO#152725/Connect#1892487). If you were triggering the atomic<UDT> bug, you’ll be greeted by a static_assert when upgrading, where I explain what’s happening: “You’ve instantiated std::atomic<T> with sizeof(T) equal to 2/4/8 and alignof(T) < sizeof(T). Before VS 2015 Update 2, this would have misbehaved at runtime. VS 2015 Update 2 was fixed to handle this correctly, but the fix inherently changes layout and breaks binary compatibility. Please define _ENABLE_ATOMIC_ALIGNMENT_FIX to acknowledge that you understand this, and that everything you’re linking has been compiled with VS 2015 Update 2 (or later).”

There’s a related bug with atomic<SizeEightAlignEight> on x86, where things are weird because the stack is only 4-aligned. Examples of SizeEightAlignEight types are: long long, double, StructWrappingLongLong, and StructWrappingDouble. During layout, the compiler has always treated these types as 8-aligned, so struct Outer { char c; SizeEightAlignEight meow; }; contains 7 bytes of padding. However, the compiler doesn’t always emit code to dynamically align the stack, so SizeEightAlignEight variables can appear on the stack at 4-byte boundaries. (This is intentional – dynamic alignment has a nonzero cost, and x86 doesn’t need long longs and doubles to be on 8-byte boundaries for correctness. Sometimes 8-byte boundaries can improve performance, so the compiler has heuristics to determine when dynamic alignment would be beneficial.)

Before Update 2, this also applied to atomic<SizeEightAlignEight> – it participated in layout with 8-alignment, but didn’t trigger dynamic alignment on the stack. This was bad, because it needs to live on 8-byte boundaries for correctness. In Update 2, this has been partially fixed. atomic<double>, atomic<StructWrappingLongLong>, and atomic<StructWrappingDouble> now have data members marked with alignas(8). This means that their layout is unchanged (so they don’t trigger the static_assert message mentioned above), but they now trigger dynamic stack alignment for correctness.

Unfortunately, I didn’t realize until just now that atomic<long long> (and atomic<unsigned long long>) were affected, and weren’t fixed in Update 2. This is because atomic<integral> specializations exist to provide integral operators, and my alignas fix affected only atomic<UDT> (which is also used by atomic<double> even though double isn’t a UDT). I’ve filed a bug assigned to myself (VSO#212461). If you’re using atomic<long long/unsigned long long> on x86, you can work around this by applying alignas yourself.

Other Fixes

* The STL now avoids emitting “warning C4265: class has virtual functions, but destructor is not virtual” (VSO#146506/Connect#1802994). This warning is off-by-default, but we’ve made a special exception to our usual policy of keeping the STL clean with respect to only those warnings that are on-by-default at /W4 /analyze.

* <cmath>: std::pow() behaved incorrectly for certain extreme inputs, like pow(2.0, -1024) (VSO#99869).

* Between RTM and Update 1, the compiler stopped exporting ctype<char>::table_size, theoretically affecting msvcp140.dll’s binary compatibility, which we’re trying very hard to preserve. Due to how table_size is used, this didn’t appear to cause trouble in practice, but it was still a bad thing (VSO#163808). The compiler was fixed for Update 2, restoring binary compatibility with RTM, and Billy added a test (later moved into the library build itself) verifying that the DLL’s exports are unchanged from RTM. This test has prevented at least one accidental case of damage (when I mistakenly tried to modify something that was exported), proving how valuable it is.

* <vector>, <string>, <deque>: We shipped C++14’s N3644 Null Forward Iterators in 2015 RTM. We implemented what the Standard specified, but it turned out that the Standard’s specification was incomplete. This feature specified that when forward iterators (provided by the Standard or by users) are value-initialized, they should be equality/inequality comparable and behave like an empty range. (Note that such iterators still can’t be compared to iterators pointing into a container, nor can iterators be compared when they point into different containers.) The problem was subtle: random-access iterators have additional operations (like subtraction), and they weren’t required to be valid for value-initialized iterators. Algorithms commonly dispatch on iterator strength, precisely because they want to do efficient things like subtract ranits. If value-initialized iterators don’t behave like an empty range, for all of the iterator operations corresponding to their strength, then they’re effectively unusable. Our implementation already allowed this in release mode, but our debug checks were overly strict. Billy audited the STL, fixing up the affected random-access iterators (in vector, string, and deque; array already worked), and adding tests so that this keeps working (VSO#199326). (I still need to file a Library Issue about this. It’s debatable whether the normative text already implies such requirements for ranit operations, but at a minimum I believe that a note needs to be added, since we didn’t originally interpret the requirements that way.)

* <algorithm>, <memory>: Starting in VS 2005, the STL has emitted warnings when algorithms like copy(first, last, result), where [first, last) is copied into [result, …), are called with raw pointers for their half-range arguments (or arbitrary iterators other than those provided by the STL itself). This is because the size of the half-range can’t be checked in debug mode. We have overloads to avoid these warnings when arrays are passed directly as arguments (as an array’s size can be detected at compile time). If you’ve ever looked at the STL’s code or debugged through it, you’ve probably seen the extensive metaprogramming required to emit these warnings. In Update 2, Billy simplified how copy()/copy_n()/copy_backward()/move()/move_backward()/uninitialized_copy() emit warnings, improving both compile-time throughput and the quality of the warning messages. (More improvements are coming in Update 3.) Additionally, fill_n() no longer emits these warnings, as while fill_n(first, n, value) takes a single iterator, it specifies a full range [first, first + n).

* Move construction of a container is supposed to move construct its allocator, but we were copy constructing (N4582 23.2.1 [container.requirements.general]/8, VSO#102478). The difference doesn’t matter for std::allocator, or most user-defined allocators, but we gotta do what the Standard says. Steve fixed up the whole STL, so now we properly move construct allocators when required.

* <typeinfo>: This header didn’t compile when _HAS_EXCEPTIONS was set to 0 (VSO#115482/Connect#1600701). This mode is currently undocumented, untested, and unsupported (which may change in the future, but not Update 2). However, this header now works with exceptions disabled.

* <algorithm>: min() and max() are now marked with conditional noexcept, strengthened from their depiction in the Standard (VSO#118461). This was an exception for an internal tool, and doesn’t represent a change in our general policy (so far, we have mostly avoided strengthening noexcept).

* Many parts of the STL are constrained to participate in overload resolution for iterators only. The internal machinery we used for this didn’t detect iterators whose iterator_category/etc. typedefs were provided non-intrusively through iterator_traits (VSO#121440). Now it does. Note that this is separate from iterator_traits SFINAE, which we have already implemented.

* <scoped_allocator>: A few compile-time errors (missing moves, etc.) have been fixed (VSO#101409, VSO#184838).

* <exception>: This header was (ironically?) missing many noexcept markings required by the Standard (VSO#121619). James fixed this, so that <exception> promises not to throw exceptions, except when it should.

* The compiler has lots of options. Some are very good (/Zc:strictStrings), some are questionable (/Gz), and some are very bad (/Zc:wchar_t-). The STL tries to tolerate almost all of them, with very few exceptions (/Zc:auto- is obviously intolerable). The /RTCc option has been very problematic (VSO#91800). Neither the compiler nor the IDE enables it by default, but if enabled (for debug builds only), it detects runtime truncation of values and terminates the program. If this happened for undefined behavior only, it would be totally awesome. Unfortunately, /RTCc detects truncation in well-defined code according to the Standard (e.g. truncating unsigned long long to unsigned short has deterministic, guaranteed behavior). It even triggers when the truncation is performed via static_cast. (Only bit-masking will appease /RTCc.) Auditing the STL for this obscure, non-Standard option is too much work for too little value. Therefore, I’ve blocked the use of /RTCc with STL headers in Update 2, with a static_assert saying: “/RTCc rejects conformant code, so it isn’t supported by the C++ Standard Library. Either remove this compiler option, or define _ALLOW_RTCc_IN_STL to acknowledge that you have received this warning.” If you enable the escape hatch, you’ll get our previous behavior, where stuff usually works.

* <utility>: Users complained that our library-only implementation of make_integer_sequence was naive and linear, which was problematic for enormous sequences (VSO#97862/Connect#1499922). They asked for some clever logarithmic implementation, as seen in other libraries. I said to myself, “That sounds hard. I’d much rather get the compiler to do my work for me.” So I requested and received a compiler hook from C1XX and Clang, which now powers make_integer_sequence (and the hook is designed so that it can power anything that behaves similarly; I was thinking of Boost). Note that as of Update 2, I still need to use the linear library-only implementation for EDG, so Intellisense might not like enormous sequences.

* <tuple>: I usually don’t count bugs that appeared and disappeared during development, but I’ll mention a last-minute fix between Update 2 RC and Update 2 RTM. When I implemented C++17’s new rules for pair/tuple in N4387, I correctly constrained tuple’s constructors, but didn’t notice how they interacted with our recursive implementation. This led to overload resolution failures with certain types (VSO#191303/Connect#2351203). I reworked tuple to avoid this problem (while leaving its representation unchanged). Now, tuple implements the C++17 rules (as modified by LWG 2549, which is necessary), to the best of my knowledge and ability. Note that these rules are a breaking change for 1-tuples, where you have a tuple<UDT> and UDT has an unconstrained templated constructor. For example, when you attempt to construct tuple<UDT> from tuple<Other>, the rules need to figure out whether you want to convert the tuples (i.e. construct UDT from Other), or whether you’re providing an argument for the contained UDT (i.e. construct UDT from tuple<Other>). If your UDT appears to be constructible from tuple<Other>, then that’s what will be selected. (LWG 2549 removes the tuple-converting constructor from consideration, for safety reasons.) If this sounds incomprehensible to you, you can safely ignore it. If you’re a maintainer of high-powered templated code that needs to interact with tuples, and your constructors aren’t properly constrained, then you do need to know about this.

* <unordered_meow>: Swapping unordered containers didn’t properly swap their max_load_factors. Actually, it swapped them twice, which was kind of bad. Now it swaps them three times. (Okay, only once.)

* <memory>: I removed a non-Standard constructor from bad_weak_ptr.

Compiler Fix

In these changelogs, I don’t list compiler fixes, even when they affect the STL. (This includes things like fixes to type traits compiler hooks.) There are simply too many compiler fixes for me to keep track of, many of which I don’t understand well. (I track everything that’s checked into the STL, plus everything that we still need from the compiler.) However, one compiler fix is worth mentioning here. When Tanveer Gani implemented constexpr in the 2015 RTM compiler, and we overhauled the STL accordingly, we almost completely avoided regressions. While many compiler bugs in constexpr have been fixed in Update 1 and Update 2 (with more coming in Update 3), pre-existing code that was using the newly constexprized STL (yet not demanding constexpr evaluation) was almost completely unaffected. The exception is that <limits> refused to compile under /Za, the “request extra conformance and sometimes extra compiler bugs” option (VSO#122298/Connect#1331482). Tanveer fixed this in Update 2, so <limits> works with /Za now. And in fact, I’ve restored /Za testing to the STL – so while we don’t recommend its use, we’ll support it.

Breaking Changes

We’re trying very hard to preserve binary compatibility in Updates, so you can do things like mix Update 2 object files with RTM static libraries. However, it’s still best to compile everything with Update 2 (this way, all of Update 2’s fixes will take effect, and you’ll get slightly smaller binaries).

As for source compatibility, you may have noticed that C++ is a complicated language. Library changes occasionally break user source code. Here are the source breaking changes that I’m aware of:

* The /RTCc block, mentioned above. Fix: Don’t use /RTCc.

* The atomic alignment fix, mentioned above. Fix: Define _ENABLE_ATOMIC_ALIGNMENT_FIX and compile everything with Update 2.

* (extremely obscure) The tr1::xor_combine and bad_weak_ptr(const char *) removals, mentioned above. Fix: Don’t use non-Standard stuff.

* As mentioned above, constructing tuple<UDT> from tuple<Other> when UDT has an (undesirably) unconstrained templated constructor, was broken by N4387 and LWG 2549. Fix: Properly constrain UDT’s templated constructor.

* Somewhat similarly, N4387 can break unusual code involving “mutating copy constructors”, see VSO#198760/Connect#2442329. Fix: Don’t imitate auto_ptr.

* Months ago, I would have sworn that std::function SFINAE was inherently non-breaking, since it merely causes the declaration of function<Signature>’s constructor from CallableObj to vanish when the definition would have exploded. But now I’ve seen two different source breaks involving squirrely user code. First, with C++11 and Update 1’s unconstrained std::function constructor, it was possible for user code to say something like decltype(user_func1(function<Signature>(bogus_callable_obj))) – or for extra mystery, decltype(user_func2(bogus_callable_obj)) where user_func2(const function<Signature>&) constructs a std::function implicitly. Such a decltype was valid, and told you what user_func1() or user_func2() would return, if called with a function<Signature> object. This worked even though actually attempting to construct function<Signature> from bogus_callable_obj (with a different signature) would fail to compile. (In the real-world example I saw, the actual construction of function<Signature> was from totally_different_callable_obj, which is how it compiled.) In C++14 and Update 2, such decltypes will fail to compile, just like actual construction would. Fix: Write your decltypes properly.

* Somewhat similarly, std::function<Ret (Args)>(callable_obj) needs to ask the questions, “can I take Args and pass them to callable_obj” and then “can I take callable_obj’s return type, and implicitly convert it to Ret”. This can reveal build breaks with forward-declared classes, involving C1XX’s “delayed template parsing”. For example, if the argument conversions or return conversion involves converting unique_ptr<Derived> to unique_ptr<Base> (which is fine, and happens implicitly), but Derived is forward-declared at the point that you construct the std::function, doom! At that point, no inheritance relationship is known between (forward-declared) Derived and Base, so the unique_ptrs don’t appear to be convertible, so the std::function doesn’t appear to be constructible. (The actual construction would have compiled previously due to the delayed template parsing, where instantiations happen at the end of the TU, when Derived’s definition is known.) Note: although C1XX’s non-Standard behavior was responsible for hiding this problem previously, this scenario (constructing std::function when Derived is forward-declared) is forbidden by the Standard. Fix: Don’t attempt to convert unique_ptrs or construct std::functions until your Derived definition has been provided.

Known Compiler Bugs Affecting Usage Of The STL

Now that you’ve heard about all of the reasons to install Update 2 (many new features and important fixes), I should mention a couple of known bugs, although they shouldn’t prevent you from installing Update 2. The compiler team fixed many bugs in Update 2, but there were a couple that we just found too late:

* After implementing P0006R0 Variable Templates For Type Traits (is_same_v, etc.), I tested them by using them in static_asserts (which are constexpr contexts). Victory! Except not. They were affected by the compiler bug VSO#202394 “Variable templates don’t work in SFINAE”, and SFINAE is a major context in which you’d want to use is_same_v/etc. Doom! This has already been fixed in C1XX for Update 3, but I noticed and reported it too late (March 15) for the fix to get into Update 2. Note that Clang was unaffected.

* I’ve received a report where the STL’s new use of a compiler hook to power make_integer_sequence (as described above) triggers compiler errors when an unrelated struct contains a typedef involving index_sequence_for (VSO#207949). This appears to be obscure, given that the STL itself uses make_integer_sequence fairly heavily (e.g. in tuple_cat()) and all of its tests are passing. If this affects you, it appears that you can work around it by using make_integer_sequence directly, instead of the index_sequence_for convenience form. (The STL does that, due to a totally unrelated compiler bug, hence its immunity.) I’ve reduced this and the compiler team will investigate fixing C1XX. Clang is unaffected.

Download Update 2

The final version of Update 2 was released on March 30. Here’s the announcement with What’s New topics for all of Visual Studio, and here’s a direct download link.

Stephan T. Lavavej (@StephanTLavavej)

Senior Developer – Visual C++ Libraries