{"id":20937,"date":"2018-10-11T14:33:39","date_gmt":"2018-10-11T14:33:39","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/vcblog\/?p=20937"},"modified":"2019-02-18T17:47:38","modified_gmt":"2019-02-18T17:47:38","slug":"how-to-use-class-template-argument-deduction","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/how-to-use-class-template-argument-deduction\/","title":{"rendered":"How to Use Class Template Argument Deduction"},"content":{"rendered":"<p><span style=\"font-family: Verdana;font-size: 12pt\">Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17&#8217;s Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector. Class templates in other libraries and your own code will partially benefit from CTAD automatically, but sometimes they&#8217;ll need a bit of new code (deduction guides) to fully benefit. Fortunately, both using CTAD and providing deduction guides is pretty easy, despite template metaprogramming&#8217;s fearsome reputation!\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">CTAD support is available in VS 2017 15.7 and later with the <a href=\"https:\/\/na01.safelinks.protection.outlook.com\/?url=https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fcpp%2Fbuild%2Freference%2Fstd-specify-language-standard-version&amp;data=02%7C01%7Cstl%40exchange.microsoft.com%7C2b73e797af314fca644108d62fbb861c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636748879932481113&amp;sdata=ctGtC8uQy8yfKcmF4QUwVhK6lS59XL6mAtdRHeJgqyk%3D&amp;reserved=0\">\/std:c++17 and \/std:c++latest<\/a> compiler options.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Template Argument Deduction\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">C++98 through C++14 performed template argument deduction for function templates. Given a function template like <code>template &lt;typename RanIt&gt; void sort(RanIt first, RanIt last);<\/code>, you can and should sort a <code>std::vector&lt;int&gt;<\/code> without explicitly specifying that <code>RanIt<\/code> is <code>std::vector&lt;int&gt;::iterator<\/code>. When the compiler sees <code>sort(v.begin(), v.end());<\/code>, it knows what the types of <code>v.begin()<\/code> and <code>v.end()<\/code> are, so it can determine what <code>RanIt<\/code> should be. The process of determining template arguments for template parameters (by comparing the types of function arguments to function parameters, according to rules in the Standard) is known as template argument deduction, which makes function templates far more usable than they would otherwise be.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">However, class templates didn&#8217;t benefit from these rules. If you wanted to construct a <code>std::pair<\/code> from two <code>int<\/code>s, you had to say <code>std::pair&lt;int, int&gt; p(11, 22);<\/code>, despite the fact that the compiler already knows that the types of <code>11<\/code> and <code>22<\/code> are <code>int<\/code>. The workaround for this limitation was to use function template argument deduction: <code>std::make_pair(11, 22)<\/code> returns <code>std::pair&lt;int, int&gt;<\/code>. Like most workarounds, this is problematic for a few reasons: defining such helper functions often involves template metaprogramming (<code>std::make_pair()<\/code> needs to perform perfect forwarding and decay, among other things), compiler throughput is reduced (as the front-end has to instantiate the helper, and the back-end has to optimize it away), debugging is more annoying (as you have to step through helper functions), and there&#8217;s still a verbosity cost (the extra <code>make_<\/code> prefix, and if you want a local variable instead of a temporary, you need to say <code>auto<\/code>).\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Hello, CTAD World\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">C++17 extends template argument deduction to the construction of an object given only the name of a class template. Now, you can say <code>std::pair(11, 22)<\/code> and this is equivalent to <code>std::pair&lt;int, int&gt;(11, 22)<\/code>. Here&#8217;s a full example, with a C++17 terse <code>static_assert<\/code> verifying that the declared type of <code>p<\/code> is the same as <code>std::pair&lt;int, const char *&gt;<\/code>:<\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type meow.cpp\r\n#include &lt;type_traits&gt;\r\n#include &lt;utility&gt;\r\nint main() {\r\n    std::pair p(1729, \"taxicab\");\r\n    static_assert(std::is_same_v&lt;decltype(p), std::pair&lt;int, const char *&gt;&gt;);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 meow.cpp\r\nmeow.cpp\r\nC:\\Temp&gt;<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">CTAD works with parentheses and braces, and named variables and nameless temporaries.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Another Example: array and greater<\/strong><\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type arr.cpp\r\n#include &lt;algorithm&gt;\r\n#include &lt;array&gt;\r\n#include &lt;functional&gt;\r\n#include &lt;iostream&gt;\r\n#include &lt;string_view&gt;\r\n#include &lt;type_traits&gt;\r\nusing namespace std;\r\nint main() {\r\n    array arr = { \"lion\"sv, \"direwolf\"sv, \"stag\"sv, \"dragon\"sv };\r\n    static_assert(is_same_v&lt;decltype(arr), array&lt;string_view, 4&gt;&gt;);\r\n    sort(arr.begin(), arr.end(), greater{});\r\n    cout &lt;&lt; arr.size() &lt;&lt; \": \";\r\n    for (const auto&amp; e : arr) {\r\n        cout &lt;&lt; e &lt;&lt; \" \";\r\n    }\r\n    cout &lt;&lt; \"\\n\";\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 arr.cpp &amp;&amp; arr\r\narr.cpp\r\n4: stag lion dragon direwolf<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">This demonstrates a couple of neat things. First, CTAD for <code>std::array<\/code> deduces both its element type and its size. Second, CTAD works with default template arguments; <code>greater{}<\/code> constructs an object of type <code>greater&lt;void&gt;<\/code> because it&#8217;s declared as <code>template &lt;typename T = void&gt; struct greater;<\/code>.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>CTAD for Your Own Types<\/strong><\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type mypair.cpp\r\n#include &lt;type_traits&gt;\r\ntemplate &lt;typename A, typename B&gt; struct MyPair {\r\n    MyPair() { }\r\n    MyPair(const A&amp;, const B&amp;) { }\r\n};\r\nint main() {\r\n    MyPair mp{11, 22};\r\n    static_assert(std::is_same_v&lt;decltype(mp), MyPair&lt;int, int&gt;&gt;);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 mypair.cpp\r\nmypair.cpp\r\nC:\\Temp&gt;<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In this case, CTAD automatically works for <code>MyPair<\/code>. What happens is that the compiler sees that a <code>MyPair<\/code> is being constructed, so it runs template argument deduction for <code>MyPair<\/code>&#8216;s constructors. Given the signature (<code>const A&amp;, const B&amp;<\/code>) and the arguments of type <code>int<\/code>, <code>A<\/code> and <code>B<\/code> are deduced to be <code>int<\/code>, and those template arguments are used for the class and the constructor.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">However, <code>MyPair{}<\/code> would emit a compiler error. That&#8217;s because the compiler would attempt to deduce <code>A<\/code> and <code>B<\/code>, but there are no constructor arguments and no default template arguments, so it can&#8217;t guess whether you want <code>MyPair&lt;int, int&gt;<\/code> or <code>MyPair&lt;Starship, Captain&gt;<\/code>.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Deduction Guides\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In general, CTAD automatically works when class templates have constructors whose signatures mention all of the class template parameters (like <code>MyPair<\/code> above). However, sometimes constructors themselves are templated, which breaks the connection that CTAD relies on. In those cases, the author of the class template can provide &#8220;deduction guides&#8221; that tell the compiler how to deduce class template arguments from constructor arguments.<\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type guides.cpp\r\n#include &lt;iterator&gt;\r\n#include &lt;type_traits&gt;\r\ntemplate &lt;typename T&gt; struct MyVec {\r\n    template &lt;typename Iter&gt; MyVec(Iter, Iter) { }\r\n};\r\ntemplate &lt;typename Iter&gt; MyVec(Iter, Iter) -&gt; MyVec&lt;typename std::iterator_traits&lt;Iter&gt;::value_type&gt;;\r\ntemplate &lt;typename A, typename B&gt; struct MyAdvancedPair {\r\n    template &lt;typename T, typename U&gt; MyAdvancedPair(T&amp;&amp;, U&amp;&amp;) { }\r\n};\r\ntemplate &lt;typename X, typename Y&gt; MyAdvancedPair(X, Y) -&gt; MyAdvancedPair&lt;X, Y&gt;;\r\nint main() {\r\n    int * ptr = nullptr;\r\n    MyVec v(ptr, ptr);\r\n    static_assert(std::is_same_v&lt;decltype(v), MyVec&lt;int&gt;&gt;);\r\n    MyAdvancedPair adv(1729, \"taxicab\");\r\n    static_assert(std::is_same_v&lt;decltype(adv), MyAdvancedPair&lt;int, const char *&gt;&gt;);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 guides.cpp\r\nguides.cpp\r\nC:\\Temp&gt;<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Here are two of the most common cases for deduction guides in the STL: iterators and perfect forwarding. <code>MyVec<\/code> resembles a <code>std::vector<\/code> in that it&#8217;s templated on an element type <code>T<\/code>, but it&#8217;s constructible from an iterator type <code>Iter<\/code>. Calling the range constructor provides the type information we want, but the compiler can&#8217;t possibly realize the relationship between <code>Iter<\/code> and <code>T<\/code>. That&#8217;s where the deduction guide helps. After the class template definition, the syntax <code>template &lt;typename Iter&gt; MyVec(Iter, Iter) -&gt; MyVec&lt;typename std::iterator_traits&lt;Iter&gt;::value_type&gt;;<\/code> tells the compiler &#8220;when you&#8217;re running CTAD for <code>MyVec<\/code>, attempt to perform template argument deduction for the signature <code>MyVec(Iter, Iter)<\/code>. If that succeeds, the type you want to construct is <code>MyVec&lt;typename std::iterator_traits&lt;Iter&gt;::value_type&gt;<\/code>. That essentially dereferences the iterator type to get the element type we want.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">The other case is perfect forwarding, where <code>MyAdvancedPair<\/code> has a perfect forwarding constructor like <code>std::pair<\/code> does. Again, the compiler sees that <code>A<\/code> and <code>B<\/code> versus <code>T<\/code> and <code>U<\/code> are different types, and it doesn&#8217;t know the relationship between them. In this case, the transformation we need to apply is different: we want <code>decay<\/code> (if you&#8217;re unfamiliar with <code>decay<\/code>, you can skip this). Interestingly, we don&#8217;t need <code>decay_t<\/code>, although we could use that type trait if we wanted extra verbosity. Instead, the deduction guide <code>template &lt;typename X, typename Y&gt; MyAdvancedPair(X, Y) -&gt; MyAdvancedPair&lt;X, Y&gt;;<\/code> is sufficient. This tells the compiler &#8220;when you&#8217;re running CTAD for <code>MyAdvancedPair<\/code>, attempt to perform template argument deduction for the signature <code>MyAdvancedPair(X, Y)<\/code>, as if it were taking arguments by value. Such deduction performs decay. If it succeeds, the type you want to construct is <code>MyAdvancedPair&lt;X, Y&gt;<\/code>.&#8221;\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">This demonstrates a critical fact about CTAD and deduction guides. CTAD looks at a class template&#8217;s constructors, plus its deduction guides, in order to determine the type to construct. That deduction either succeeds (determining a unique type) or fails. Once the type to construct has been chosen, overload resolution to determine which constructor to call happens normally. <strong>CTAD doesn&#8217;t affect how the constructor is called.<\/strong> For <code>MyAdvancedPair<\/code> (and <code>std::pair<\/code>), the deduction guide&#8217;s signature (taking arguments by value, notionally) affects the type chosen by CTAD. Afterwards, overload resolution chooses the perfect forwarding constructor, which takes its arguments by perfect forwarding, exactly as if the class type had been written with explicit template arguments.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">CTAD and deduction guides are also non-intrusive. Adding deduction guides for a class template doesn&#8217;t affect existing code, which previously was required to provide explicit template arguments. That&#8217;s why we were able to add deduction guides for many STL types without breaking a single line of user code.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Enforcement\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In rare cases, you might want deduction guides to reject certain code. Here&#8217;s how <code>std::array<\/code> does it:<\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type enforce.cpp\r\n#include &lt;stddef.h&gt;\r\n#include &lt;type_traits&gt;\r\ntemplate &lt;typename T, size_t N&gt; struct MyArray {\r\n    T m_array[N];\r\n};\r\ntemplate &lt;typename First, typename... Rest&gt; struct EnforceSame {\r\n    static_assert(std::conjunction_v&lt;std::is_same&lt;First, Rest&gt;...&gt;);\r\n    using type = First;\r\n};\r\ntemplate &lt;typename First, typename... Rest&gt; MyArray(First, Rest...)\r\n    -&gt; MyArray&lt;typename EnforceSame&lt;First, Rest...&gt;::type, 1 + sizeof...(Rest)&gt;;\r\nint main() {\r\n    MyArray a = { 11, 22, 33 };\r\n    static_assert(std::is_same_v&lt;decltype(a), MyArray&lt;int, 3&gt;&gt;);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 enforce.cpp\r\nenforce.cpp\r\nC:\\Temp&gt;<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Like <code>std::array<\/code>, <code>MyArray<\/code> is an aggregate with no actual constructors, but CTAD still works for these class templates via deduction guides. <code>MyArray<\/code>&#8216;s guide performs template argument deduction for <code>MyArray(First, Rest...)<\/code>, enforcing all of the types to be the same, and determining the array&#8217;s size from how many arguments there are.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Similar techniques could be used to make CTAD entirely ill-formed for certain constructors, or all constructors. The STL itself hasn&#8217;t needed to do that explicitly, though. (There are only two classes where CTAD would be undesirable: <code>unique_ptr<\/code> and <code>shared_ptr<\/code>. C++17 supports both <code>unique_ptrs<\/code> and <code>shared_ptrs<\/code> to arrays, but both <code>new T<\/code> and <code>new T[N]<\/code> return <code>T *<\/code>. Therefore, there&#8217;s insufficient information to safely deduce the type of a <code>unique_ptr<\/code> or <code>shared_ptr<\/code> being constructed from a raw pointer. As it happens, this is automatically blocked in the STL due to <code>unique_ptr<\/code>&#8216;s support for fancy pointers and <code>shared_ptr<\/code>&#8216;s support for type erasure, both of which change the constructor signatures in ways that prevent CTAD from working.)\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Corner Cases for Experts: Non-Deduced Contexts\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Here are some advanced examples that aren&#8217;t meant to be imitated; instead, they&#8217;re meant to illustrate how CTAD works in complicated scenarios.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Programmers who write function templates eventually learn about &#8220;non-deduced contexts&#8221;. For example, a function template taking <code>typename Identity&lt;T&gt;::type<\/code> can&#8217;t deduce <code>T<\/code> from that function argument. Now that CTAD exists, non-deduced contexts affect the constructors of class templates too.<\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type corner1.cpp\r\ntemplate &lt;typename X&gt; struct Identity {\r\n    using type = X;\r\n};\r\ntemplate &lt;typename T&gt; struct Corner1 {\r\n    Corner1(typename Identity&lt;T&gt;::type, int) { }\r\n};\r\nint main() {\r\n    Corner1 corner1(3.14, 1729);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 corner1.cpp\r\ncorner1.cpp\r\ncorner1.cpp(10): error C2672: 'Corner1': no matching overloaded function found\r\ncorner1.cpp(10): error C2783: 'Corner1&lt;T&gt; Corner1(Identity&lt;X&gt;::type,int)': could not deduce template argument for 'T'\r\ncorner1.cpp(6): note: see declaration of 'Corner1'\r\ncorner1.cpp(10): error C2641: cannot deduce template argument for 'Corner1'\r\ncorner1.cpp(10): error C2514: 'Corner1': class has no constructors\r\ncorner1.cpp(5): note: see declaration of 'Corner1'<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In corner1.cpp, <code>typename Identity&lt;T&gt;::type<\/code> prevents the compiler from deducing that <code>T<\/code> should be <code>double<\/code>.\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Here&#8217;s a case where some but not all constructors mention <code>T<\/code> in a non-deduced context:<\/span><\/p>\n<pre class=\"lang:default decode:true\">C:\\Temp&gt;type corner2.cpp\r\ntemplate &lt;typename X&gt; struct Identity {\r\n    using type = X;\r\n};\r\ntemplate &lt;typename T&gt; struct Corner2 {\r\n    Corner2(T, long) { }\r\n    Corner2(typename Identity&lt;T&gt;::type, unsigned long) { }\r\n};\r\nint main() {\r\n    Corner2 corner2(3.14, 1729);\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 corner2.cpp\r\ncorner2.cpp\r\ncorner2.cpp(11): error C2668: 'Corner2&lt;double&gt;::Corner2': ambiguous call to overloaded function\r\ncorner2.cpp(7): note: could be 'Corner2&lt;double&gt;::Corner2(double,unsigned long)'\r\ncorner2.cpp(6): note: or       'Corner2&lt;double&gt;::Corner2(T,long)'\r\n        with\r\n        [\r\n            T=double\r\n        ]\r\ncorner2.cpp(11): note: while trying to match the argument list '(double, int)'<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In corner2.cpp, CTAD succeeds but constructor overload resolution fails. CTAD ignores the constructor taking <code>(typename Identity&lt;T&gt;::type, unsigned long)<\/code> due to the non-deduced context, so CTAD uses only <code>(T, long)<\/code> for deduction. Like any function template, comparing the parameters <code>(T, long)<\/code> to the argument types <code>double, int<\/code> deduces <code>T<\/code> to be <code>double<\/code>. (int is convertible to <code>long<\/code>, which is sufficient for template argument deduction; it doesn&#8217;t demand an exact match there.) After CTAD has determined that <code>Corner2&lt;double&gt;<\/code> should be constructed, constructor overload resolution considers both signatures <code>(double, long)<\/code> and <code>(double, unsigned long)<\/code> after substitution, and those are ambiguous for the argument types <code>double, int<\/code> (because <code>int<\/code> is convertible to both <code>long<\/code> and <code>unsigned long<\/code>, and the Standard doesn&#8217;t prefer either conversion).\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Corner Cases for Experts: Deduction Guides Are Preferred<\/strong><\/span><\/p>\n<pre class=\"lang:default decode:true \">C:\\Temp&gt;type corner3.cpp\r\n#include &lt;type_traits&gt;\r\ntemplate &lt;typename T&gt; struct Corner3 {\r\n    Corner3(T) { }\r\n    template &lt;typename U&gt; Corner3(U) { }\r\n};\r\n#ifdef WITH_GUIDE\r\n    template &lt;typename X&gt; Corner3(X) -&gt; Corner3&lt;X *&gt;;\r\n#endif\r\nint main() {\r\n    Corner3 corner3(1729);\r\n#ifdef WITH_GUIDE\r\n    static_assert(std::is_same_v&lt;decltype(corner3), Corner3&lt;int *&gt;&gt;);\r\n#else\r\n    static_assert(std::is_same_v&lt;decltype(corner3), Corner3&lt;int&gt;&gt;);\r\n#endif\r\n}\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 corner3.cpp\r\ncorner3.cpp\r\nC:\\Temp&gt;cl \/EHsc \/nologo \/W4 \/std:c++17 \/DWITH_GUIDE corner3.cpp\r\ncorner3.cpp\r\nC:\\Temp&gt;<\/pre>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">CTAD works by performing template argument deduction and overload resolution for a set of deduction candidates (hypothetical function templates) that are generated from the class template&#8217;s constructors and deduction guides. In particular, this follows the usual rules for overload resolution with only a couple of additions. Overload resolution still prefers things that are more specialized (N4713 16.3.3 [over.match.best]\/1.7). When things are equally specialized, there&#8217;s a new tiebreaker: deduction guides are preferred (\/1.12).\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">In corner3.cpp, without a deduction guide, the <code>Corner3(T)<\/code> constructor is used for CTAD (whereas <code>Corner3(U)<\/code> isn&#8217;t used for CTAD because it doesn&#8217;t mention T), and <code>Corner3&lt;int&gt;<\/code> is constructed. When the deduction guide is added, the signatures <code>Corner3(T)<\/code> and <code>Corner3(X)<\/code> are equally specialized, so paragraph \/1.12 steps in and prefers the deduction guide. This says to construct <code>Corner3&lt;int *&gt;<\/code> (which then calls <code>Corner3(U)<\/code> with <code>U = int<\/code>).\n<\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\"><strong>Reporting Bugs\n<\/strong><\/span><\/p>\n<p><span style=\"font-family: Verdana;font-size: 12pt\">Please let us know what you think about VS. You can report bugs via the IDE&#8217;s Report A Problem and also via the web: go to the <a href=\"https:\/\/na01.safelinks.protection.outlook.com\/?url=https%3A%2F%2Fdevelopercommunity.visualstudio.com%2F&amp;data=02%7C01%7Cstl%40exchange.microsoft.com%7C2b73e797af314fca644108d62fbb861c%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636748879932481113&amp;sdata=xd7N3CE6%2F3wWoM3BGGBAMC1Oyx2rZz9iFWATjsjscnA%3D&amp;reserved=0\">VS Developer Community<\/a> and click on the C++ tab.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17&#8217;s Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector. Class templates in other libraries and your own code will partially benefit from [&hellip;]<\/p>\n","protected":false},"author":266,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[512],"tags":[],"class_list":["post-20937","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general-cpp-series"],"acf":[],"blog_post_summary":"<p>Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17&#8217;s Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector. Class templates in other libraries and your own code will partially benefit from [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20937","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/266"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=20937"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20937\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=20937"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=20937"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=20937"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}