|
| 1 | +--- |
| 2 | +title: "C++ compiler conformance improvements | Microsoft Docs" |
| 3 | +ms.custom: "" |
| 4 | +ms.date: "11/16/2016" |
| 5 | +ms.prod: "visual-studio-dev15" |
| 6 | +ms.reviewer: "" |
| 7 | +ms.suite: "" |
| 8 | +ms.technology: |
| 9 | + - "vs-ide-general" |
| 10 | +ms.tgt_pltfrm: "" |
| 11 | +ms.topic: "article" |
| 12 | +ms.assetid: 8801dbdb-ca0b-491f-9e33-01618bff5ae9 |
| 13 | +author: "BrianPeek" |
| 14 | +ms.author: "brpeek" |
| 15 | +manager: "ghogen" |
| 16 | +translation.priority.ht: |
| 17 | + - "cs-cz" |
| 18 | + - "de-de" |
| 19 | + - "es-es" |
| 20 | + - "fr-fr" |
| 21 | + - "it-it" |
| 22 | + - "ja-jp" |
| 23 | + - "ko-kr" |
| 24 | + - "pl-pl" |
| 25 | + - "pt-br" |
| 26 | + - "ru-ru" |
| 27 | + - "tr-tr" |
| 28 | + - "zh-cn" |
| 29 | + - "zh-tw" |
| 30 | +--- |
| 31 | + |
| 32 | +# C++ conformance improvements in [!INCLUDE[vs_dev15_md](../misc/includes/vs_dev15_md.md)] |
| 33 | +In this release, we've updated the C++ compiler and standard library with enhanced support for C++11 and C++14 features, as well as preliminary support for certain features expected to be in the C++17 standard. With support for generalized constexpr and NSDMI for aggregates, the compiler is complete for features added in the C++14 Standard. Note that the compiler still lacks a few features from the C++11 and C++98 Standards. |
| 34 | + |
| 35 | +## New language features |
| 36 | + |
| 37 | +### Standards version switches |
| 38 | +New compiler switches enable you to opt-in to specific versions of the ISO C++ programming language in a project. The switches available in Visual Studio 2017 are /std:c++14 and /std:c++latest. For more information, see [Standards version switches in the compiler](https://blogs.msdn.microsoft.com/vcblog/2016/06/07/standards-version-switches-in-the-compiler). Most of the new draft standard features are guarded by the /std:c++latest switch. |
| 39 | + |
| 40 | +### C++11: |
| 41 | +**Expression SFINAE (via more libraries)support in more libraries** |
| 42 | +The Visual C++ compiler is now capable continues to improve its support for expression SFINAE, which is required for template argument deduction and substitution where decltype and constexpr expressions may appear as template parameters. For more information, see [Expression SFINAE improvements in VS 2015 Update 3](https://blogs.msdn.microsoft.com/vcblog/2016/06/07/expression-sfinae-improvements-in-vs-2015-update-3). |
| 43 | + |
| 44 | + |
| 45 | +### C++ 14: |
| 46 | +**NSDMI for Aggregates** |
| 47 | +An aggregate is an array or a class with no user-provided constructor, no private or protected non-static data members, no base classes, and no virtual functions. Beginning in C++14 aggregates may contain member initializers. For more information, see [Member initializers and aggregates](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3605.html). |
| 48 | + |
| 49 | +**Extended constexpr** |
| 50 | +Expressions declared as constexpr are now allowed to contain certain kinds of declarations, if and switch statements, loop statements, and mutation of objects whose lifetime began within the constexpr expression evaluation. Also, there is no longer a requirement that a constexpr non-static member function be implicitly const. For more information, see [Relaxing constraints on constexpr functions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html). |
| 51 | + |
| 52 | +### C++17 (available with /std:c++latest): |
| 53 | +**Terse static_assert** (available with /std:c++latest) |
| 54 | +In C++17 the message parameter for static_assert is optional. For more information, see [Extending static_assert, v2](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3928.pdf). |
| 55 | + |
| 56 | +**[[fallthrough]] attribute** (available with /std:c++latest) |
| 57 | +The [[fallthrough]] attribute can be used in the context of switch statements as a hint to the compiler that the fall-through behavior is intended. This prevents the compiler from issuing warnings in such cases. For more information, see [Wording for [[fallthrough]] attribute](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0188r0.pdf). |
| 58 | + |
| 59 | +**Generalized range-based for loops** (no compiler switch required) |
| 60 | +Range-based for loops no longer require that begin() and end() return objects of the same type. This enables end() to return a sentinel object such as used by ranges as defined in the Ranges-V3 proposal. For more information, see [Generalizing the Range-Based For Loop](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0184r0.html) and the [range-v3 library on GitHub](https://github.com/ericniebler/range-v3). |
| 61 | + |
| 62 | + |
| 63 | +For the complete list of conformance improvements up through Visual Studio 2015, Update 3, see [Visual C++ What's New 2003 through 2015](https://msdn.microsoft.com/en-us/library/mt723604.aspx). |
| 64 | + |
| 65 | + |
| 66 | + |
| 67 | +## Bug fixes |
| 68 | +### Copy-list-initialization |
| 69 | +Visual Studio 2017 correctly raises compiler errors related to object creation using initializer lists that were not caught in Visual Studio 2015 and could lead to crashes or undefined runtime behavior. In copy-list-initialization, the compiler is required to consider an explicit constructor for overload resolution, but must raise an error if that overload is actually chosen. |
| 70 | +The following two examples compile in Visual Studio 2015 but not in Visual Studio 2017. |
| 71 | +```cpp |
| 72 | +struct A |
| 73 | +{ |
| 74 | + explicit A(int) {} |
| 75 | + A(double) {} |
| 76 | +}; |
| 77 | + |
| 78 | +int main() |
| 79 | +{ |
| 80 | + A a1 = { 1 }; // error C3445: copy-list-initialization of 'A' cannot use an explicit constructor |
| 81 | + const A& a2 = { 1 }; // error C2440: 'initializing': cannot convert from 'int' to 'const A &' |
| 82 | + |
| 83 | +} |
| 84 | +``` |
| 85 | +To correct the error, use direct initialization: |
| 86 | +```cpp |
| 87 | +A a1{ 1 }; |
| 88 | +const A& a2{ 1 }; |
| 89 | +``` |
| 90 | + |
| 91 | +In Visual Studio 2015, the compiler erroneously treated copy-list-initialization in the same way as regular copy-initialization; it considered only converting constructors for overload resolution. In the following example, Visual Studio 2015 chooses MyInt(23) but Visual Studio 2017 correctly raises the error. |
| 92 | + |
| 93 | +```cpp |
| 94 | +// From http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1228 |
| 95 | +struct MyList { |
| 96 | + explicit MyStore(int initialCapacity); |
| 97 | +}; |
| 98 | + |
| 99 | +struct MyInt { |
| 100 | + MyInt(int i); |
| 101 | +}; |
| 102 | + |
| 103 | +struct Printer { |
| 104 | + void operator()(MyStore const& s); |
| 105 | + void operator()(MyInt const& i); |
| 106 | +}; |
| 107 | + |
| 108 | +void f() { |
| 109 | + Printer p; |
| 110 | + p({ 23 }); // C3066: there are multiple ways that an object of this type can be called with these arguments |
| 111 | +} |
| 112 | +``` |
| 113 | +
|
| 114 | +This example is similar to the previous one but raises a different error. It succeeds in Visual Studio 2015 and fails in Visual Studio 2017 with C2668. |
| 115 | +
|
| 116 | +```cpp |
| 117 | +struct A { |
| 118 | + explicit A(int) {} |
| 119 | +}; |
| 120 | +
|
| 121 | +struct B { |
| 122 | + B(int) {} |
| 123 | +}; |
| 124 | +
|
| 125 | +void f(const A&) {} |
| 126 | +void f(const B&) {} |
| 127 | +
|
| 128 | +int main() |
| 129 | +{ |
| 130 | + f({ 1 }); // error C2668: 'f': ambiguous call to overloaded function |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +### Deprecated typedefs |
| 135 | +Visual Studio 2017 now issues the correct warning for deprecated typedefs that are declared in a class or struct. The following example compiles without warnings in Visual Studio 2015 but produces C4996 in Visual Studio 2017. |
| 136 | + |
| 137 | +```cpp |
| 138 | +struct A |
| 139 | +{ |
| 140 | + // also for __declspec(deprecated) |
| 141 | + [[deprecated]] typedef int inttype; |
| 142 | +}; |
| 143 | + |
| 144 | +int main() |
| 145 | +{ |
| 146 | + A::inttype a = 0; // C4996 'A::inttype': was declared deprecated |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +### constexpr |
| 151 | +Visual Studio 2017 correctly raises an error when the left-hand operand of a conditionally evaluating operation is not valid in a constexpr context. The following code compiles in Visual Studio 2015 but not in Visual Studio 2017: |
| 152 | + |
| 153 | +```cpp |
| 154 | +template<int N> |
| 155 | +struct array |
| 156 | +{ |
| 157 | + int size() const { return N; } |
| 158 | +}; |
| 159 | + |
| 160 | +constexpr bool f(const array<1> &arr) |
| 161 | +{ |
| 162 | + return arr.size() == 10 || arr.size() == 11; // error starting in Visual Studio 2017 |
| 163 | +} |
| 164 | +``` |
| 165 | +To correct the error, either declare the array::size() function as constexpr or remove the constexpr qualifier from f. |
| 166 | +
|
| 167 | +### Class types passed to variadic functions |
| 168 | +In Visual Studio 2017, classes or structs that are passed to a variadic function such as printf must be trivially copyable. When passing such objects, the compiler simply makes a bitwise copy and does not call the constructor or destructor. |
| 169 | +
|
| 170 | +```cpp |
| 171 | +#include <atomic> |
| 172 | +#include <memory> |
| 173 | +#include <stdio.h> |
| 174 | +
|
| 175 | +int main() |
| 176 | +{ |
| 177 | + std::atomic<int> i(0); |
| 178 | + printf("%i\n", i); // error C4839: non-standard use of class 'std::atomic<int>' |
| 179 | + // as an argument to a variadic function |
| 180 | + // note: the constructor and destructor will not be called; |
| 181 | + // a bitwise copy of the class will be passed as the argument |
| 182 | + // error C2280: 'std::atomic<int>::atomic(const std::atomic<int> &)': |
| 183 | + // attempting to reference a deleted function |
| 184 | +
|
| 185 | + struct S { |
| 186 | + S(int i) : i(i) {} |
| 187 | + S(const S& other) : i(other.i) {} |
| 188 | + operator int() { return i; } |
| 189 | + private: |
| 190 | + int i; |
| 191 | + } s(0); |
| 192 | + printf("%i\n", s); // warning C4840 : non-portable use of class 'main::S' |
| 193 | + // as an argument to a variadic function |
| 194 | +} |
| 195 | +``` |
| 196 | +To correct the error, you can callC2672 a member function that returns a trivially copyable type, |
| 197 | + |
| 198 | +```cpp |
| 199 | + std::atomic<int> i(0); |
| 200 | + printf("%i\n", i.load()); |
| 201 | +``` |
| 202 | +or else perform a static cast to convert the object before passing it: |
| 203 | +```cpp |
| 204 | + struct S {/* as before */} s(0); |
| 205 | + printf("%i\n", static_cast<int>(s)) |
| 206 | +``` |
| 207 | +For strings built and managed using CStringW, the provided ‘operator LPCWSTR()’ should be used to cast a CStringW object to the C pointer expected by the format string. |
| 208 | +```cpp |
| 209 | +CStringW str1; |
| 210 | +CStringW str2; |
| 211 | +str1.Format(… , static_cast<LPCWSTR>(str2)); |
| 212 | +``` |
| 213 | + |
| 214 | +### cv-qualifiers in class construction |
| 215 | +In Visual Studio 2015, the compiler sometimes incorrectly ignores the cv-qualifier when generating a class object via a constructor call. This can potentially cause a crash or unexpected runtime behavior. The following example compiles in Visual Studio 2015 but raises a compiler error in Visual Studio 2017: |
| 216 | + |
| 217 | +```cpp |
| 218 | +struct S |
| 219 | +{ |
| 220 | + S(int); |
| 221 | + operator int(); |
| 222 | +}; |
| 223 | + |
| 224 | +int i = (const S)0; // error C2440 |
| 225 | +``` |
| 226 | +To correct the error, declare operator int() as const. |
| 227 | +
|
| 228 | +### Access checking on qualified names in templates |
| 229 | +Previous versions of the compiler did not perform access checking on qualified names in some template contexts. This can interfere with expected SFINAE behavior where the substitution is expected to fail due to the inaccessibility of a name. This could have potentially caused a crash or unexpected behavior at runtime due to the compiler incorrectly calling the wrong overload of the operator. In Visual Studio 2017, a compiler error is raised. The specific error might vary but typically it is "C2672 no matching overloaded function found". The following code compiles in Visual Studio 2015 but raises an error in Visual Studio 2017: |
| 230 | +
|
| 231 | +```cpp |
| 232 | +#include <type_traits> |
| 233 | +
|
| 234 | +template <class T> class S { |
| 235 | + typedef typename T type; |
| 236 | +}; |
| 237 | +
|
| 238 | +template <class T, std::enable_if<std::is_integral<typename S<T>::type>::value, T> * = 0> |
| 239 | +bool f(T x); |
| 240 | +
|
| 241 | +int main() |
| 242 | +{ |
| 243 | + f(10); // C2672: No matching overloaded function found. |
| 244 | +} |
| 245 | +``` |
| 246 | + |
| 247 | +### Missing template argument lists |
| 248 | +In Visual Studio 2015 and earlier, the compiler did not diagnose missing template argument lists when the template appeared in a template parameter list (for example as part of a default template argument or a non-type template parameter). This can result in unpredictable behavior, including compiler crashes or unexpected runtime behavior. The following code compiles in Visual Studio 2015 but produces an error in Visual Studio 2017. |
| 249 | + |
| 250 | +```cpp |
| 251 | +template <class T> class ListNode; |
| 252 | +template <class T> using ListNodeMember = ListNode<T> T::*; |
| 253 | +template <class T, ListNodeMember M> class ListHead; // C2955: 'ListNodeMember': use of alias template requires template argument list |
| 254 | + |
| 255 | +// correct: template <class T, ListNodeMember<T> M> class ListHead; |
| 256 | +``` |
| 257 | +
|
| 258 | +### Expression-SFINAE |
| 259 | +As part of supporting expression-SFINAE the compiler now parses decltype arguments when the templates are declared rather than instantiated. Consequently, if a non-dependent specialization is found in the decltype argument, it will not be deferred to instantiation-time and will be processed immediately and any resulting errors will be diagnosed at that time. |
| 260 | +The following example shows such a compiler error that is raised at the point of declaration: |
| 261 | +
|
| 262 | +```cpp |
| 263 | +#include <utility> |
| 264 | +template <class T, class ReturnT, class... ArgsT> class IsCallable |
| 265 | +{ |
| 266 | +public: |
| 267 | + struct BadType {}; |
| 268 | + template <class U> |
| 269 | + static decltype(std::declval<T>()(std::declval<ArgsT>()...)) Test(int); //C2064. Should be declval<U> |
| 270 | + template <class U> |
| 271 | + static BadType Test(...); |
| 272 | + static constexpr bool value = std::is_convertible<decltype(Test<T>(0)), ReturnT>::value; |
| 273 | +}; |
| 274 | +
|
| 275 | +constexpr bool test1 = IsCallable<int(), int>::value; |
| 276 | +static_assert(test1, "PASS1"); |
| 277 | +constexpr bool test2 = !IsCallable<int*, int>::value; |
| 278 | +static_assert(test2, "PASS2"); |
| 279 | +``` |
| 280 | + |
| 281 | +### Default initializers for value class members (C++/CLI) |
| 282 | +In Visual Studio 2015 and earlier, the compiler permitted (but ignored) a default member initializer for a member of a value class. Default initialization of a value class always zero-initializes the members; a default constructor is not permitted. In Visual Studio 2017, default member initializers raise a compiler error, as shown in this example: |
| 283 | + |
| 284 | +```cpp |
| 285 | +value struct V |
| 286 | +{ |
| 287 | + int i = 0; // error C3446: 'V::i': a default member initializer is not allowed for a member of a value class |
| 288 | +}; |
| 289 | +``` |
| 290 | + |
| 291 | +### Default Indexers (C++/CLI) |
| 292 | +In Visual Studio 2015 and earlier, the compiler in some cases misidentified a default property as a default indexer. It was possible to work around the issue by using the identifier "default" to access the property. The workaround itself became problematic after default was introduced as a keyword in C++11. Therefore, in Visual Studio 2017 the bugs that required the workaround were fixed, and the compiler now raises an error when "default" is used to access the default property for a class. |
| 293 | + |
| 294 | +```cpp |
| 295 | +//class1.cs |
| 296 | + |
| 297 | +using System.Reflection; |
| 298 | +using System.Runtime.InteropServices; |
| 299 | + |
| 300 | +namespace ClassLibrary1 |
| 301 | +{ |
| 302 | + [DefaultMember("Value")] |
| 303 | + public class Class1 |
| 304 | + { |
| 305 | + public int Value |
| 306 | + { |
| 307 | + // using attribute on the return type triggers the compiler bug |
| 308 | + [return: MarshalAs(UnmanagedType.I4)] |
| 309 | + get; |
| 310 | + } |
| 311 | + } |
| 312 | + [DefaultMember("Value")] |
| 313 | + public class Class2 |
| 314 | + { |
| 315 | + public int Value |
| 316 | + { |
| 317 | + get; |
| 318 | + } |
| 319 | + } |
| 320 | +} |
| 321 | + |
| 322 | + |
| 323 | +// code.cpp |
| 324 | +#using "class1.dll" |
| 325 | + |
| 326 | +void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2) |
| 327 | +{ |
| 328 | + r1->Value; // error |
| 329 | + r1->default; |
| 330 | + r2->Value; |
| 331 | + r2->default; // error |
| 332 | +} |
| 333 | +``` |
| 334 | +
|
| 335 | +In Visual Studio 2017, you can access both Value properties by their name: |
| 336 | +
|
| 337 | +```cpp |
| 338 | +#using "class1.dll" |
| 339 | +
|
| 340 | +void f(ClassLibrary1::Class1 ^r1, ClassLibrary1::Class2 ^r2) |
| 341 | +{ |
| 342 | + r1->Value; |
| 343 | + r2->Value; |
| 344 | +} |
| 345 | +``` |
| 346 | + |
| 347 | + |
0 commit comments