Visual Studio 2012 has fixed a lot of bugs in C++11 features which were present in Visual Studio 2010.
Of course, VS2010 was released before the C++ standard was finalised. Now that the standard is final, Visual Studio doesn’t have to follow a moving target, and its compliance with the standard is getting a lot better.
This means that you can drop a lot of the workarounds or start using features you’ve previously avoided. Your code can be cleaner and more straightforward.
Let’s have a look at some of the bugs which are now history…
Using lambdas in the previous version of Visual Studio required you to tread carefully.
1 One bug in VS2010 was to do with nested lambdas and capturing variables. Consider this code:
If I change the capture lists from using the default mode to capturing power_level explicitly, the code will no longer compile in VS2010 because the compiler thinks power_level isn’t accessible to the inner lambda:
The workaround is either to use a default capture mode (as in the original example), or to copy power_level into a local variable in the outer lambda and capture the copy in the inner lambda.
2 Another, more insidious problem occurred due to a combination of storing lambdas in an array and instantiating a type with a constructor in one of the lambdas. This code, for example, resulted in a crash (sometimes):
Note string s constructed in the second lambda. This is what caused the crash.
3 One more problematic example was a combination of a templated class, a lambda expression and an initializer list. This code didn’t compile in VS2010:
The workaround was to initialize _f in the body of the constructor instead, but it’s no longer necessary.
4 You couldn’t use a static variable in a lambda within a template function:
5 Yet another bug related to static variables also involved initializer lists:
You could expect a lot of issues with non-trivial uses of decltype. Its current implementation works a lot better.
6 decltype for member types
In addition to letting you use decltype to declare variables using the type of a previous variable, the VS2012 compiler has been fixed to allow you to do the same with class member variables:
declval is now included, so you have the ability to use classes with no default constructor as decltype expressions:
You should no longer need to roll your own declval.
8 Comma operator in decltype expressions
As you probably know, if you want decltype to yield a reference type, you need to put the argument expression in parentheses:
However, before VS2012, if your expression included the comma operator, decltype failed to return a reference type. This is now fixed:
9 You could compile this code in VS2010:
The last line invoked the deleter and in this instance caused a crash. The standard doesn’t define operator() for unique_ptr, however in the VS2010 implementation unique_ptr derived from empty deleters to take advantage of the empty base class optimization, thus exposing the deleter’s operator(). This is fixed in VS2012 by using private inheritance to prevent the empty deleter’s function call operator from being part of the unique_ptr interface.
10 It was possible to store function pointers in a tuple, but it wasn’t possible to use make_tuple to store a reference to a function. In theory, a tuple can be constructed manually to store a function reference, but that didn’t work in VS2010:
11 VS2010 didn’t have the tuple_cat template to concatenate tuples, so you couldn’t do this:
Both of these issues have been rectified.
12 Since lambdas are essentially function objects, it should be possible to use them with bind. However, bind relies on the result_of template to figure out the return type of function objects. VS2010 has a pre-C++11 implementation of this template which can’t evaluate the return type of lambdas, and it made lambdas impossible to use with bind.
The workaround is to wrap a lambda with std::function and then pass it to bind.
13 The VS2010 implementation of bind didn’t allow the use of move-only types, so you couldn’t write this:
In VS2012, you can combine bind with lambdas and move-only types to your heart’s content.
emplace member functions
14 emplace()/emplace_back()/emplace_front() are intended to construct elements in place instead of moving/copying an object into the container, and they are supposed to take arguments for the element’s constructor rather than the element itself as a parameter. However, due to the lack of variadic templates, Visual Studio 2010 provided these functions with non-standard signatures, merely as synonyms to the insert and push*_ operations. With Visual Studio 2012, these functions became useful (although they still support a limited number of arguments):
15 to_string()/to_wstring() overloads for types other than long long, unsigned long long, and long double were missing, causing ambiguity if you tried to pass these functions an int or a double.
Type traits bugs
16 The type_traits library had quite a few issues with rvalue references.
is_rvalue_reference failed when passed either an lvalue reference or an rvalue reference to a function:
is_reference returned the wrong value when passed an rvalue reference to a function:
is_function and is_object couldn’t handle rvalue references:
Other VS2010 type properties templates also had problems with rvalue reference support:
All of these issues have been rectified.
17 When both arguments of common_type are the same type which is char, unsigned char, short or unsigned short, the result of common_type was incorrectly evaluated to be int:
This is no longer a problem.
In VS2010, common_type only worked with precisely 2 arithmetic types instead of 1 or more types (presumably because of the lack of variadic templates). Now it works with 7-12 types, depending on compiler settings.
18 is_trivial and is_standard_layout templates were synonyms for is_pod in VS2010, which isn’t correct, and as a result the queries in the following example produced wrong results:
19 A lot of type property templates were missing in VS2010 and have been added to VS2012:
20 The sign conversion templates weren’t very well behaved in VS2010.
make_signed lost const and volatile qualifiers in all unsigned to signed type conversions:
make_signed converted some integer types incorrectly (although the result types happen to use the right number of bytes for storage):
Similarly, make_unsigned converted long to int, and lost const and volatile qualifiers (in signed to unsigned conversions in this case).
21 underlying_type for determining the underlying type of an enum wasn’t available.
22 Instead of specifying the number of buckets, you should be able to specify the expected number of elements with reserve(), however this wasn’t implemented:
23 Instead of providing make_exception_ptr() to create an exception_ptr that refers to a copy of the function’s argument, VS2010 provided non-standard copy_exception() to perform the same job.
The logical question to ask after all this is…
Is Visual Studio 2012 C++11 support totally bug free?
The answer is no. Visual Studio 2012 still has bugs in C++11 features (luckily, most of them can be worked around). There isn’t much overlap between VS2010 and VS2012 though - the bugs are mostly different.
I’m hard at work on the VS2012 edition of C++11 Rocks. The first 13 chapters are already available. With this book, you can quickly learn all the intricate details of the C++11 features available in Visual Studio 2012 - bugs and all.