{"id":25034,"date":"2019-10-01T14:52:46","date_gmt":"2019-10-01T14:52:46","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=25034"},"modified":"2019-10-01T14:52:46","modified_gmt":"2019-10-01T14:52:46","slug":"c20s-conditionally-explicit-constructors","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/c20s-conditionally-explicit-constructors\/","title":{"rendered":"C++20&#8217;s Conditionally Explicit Constructors"},"content":{"rendered":"<p><code>explicit(bool)<\/code> is a C++20 feature for simplifying the implementation of generic types and improving compile-time performance.<\/p>\n<p>In C++ it is common to write and use types which wrap objects of other types. <code>std::pair<\/code> and <code>std::optional<\/code> are two examples, but there are plenty of others in the standard library, Boost, and likely your own codebases. Following the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Principle_of_least_astonishment\">principle of least astonishment<\/a>, it pays to ensure that these wrappers preserve the behavior of their stored types as much as is reasonable.<\/p>\n<p>Take <code>std::string<\/code> as an example. It allows implicit conversion from a string literal, but <em>not<\/em> from a <code>std::string_view<\/code>:<\/p>\n<pre class=\"lang:default decode:true\">void f(std::string);\r\n\r\nf(\u201chello\u201d);   \/\/compiles\r\nf(\u201chello\u201dsv); \/\/compiler error<\/pre>\n<p>This is achieved in <code>std::string<\/code> by marking the constructor which takes a <code>std::string_view<\/code> as <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/explicit\">explicit<\/a>.<\/p>\n<p>If we are writing a wrapper type, then in many cases we would want to expose the same behaviour, i.e. if the stored type allows implicit conversions, then so does our wrapper; if the stored type does not, then our wrapper follows<sup><a id=\"post-25026-footnote-ref-2\" href=\"#post-25026-footnote-2\">[1]<\/a><\/sup>. More concretely:<\/p>\n<pre class=\"lang:default decode:true\">void g(wrapper&lt;std::string&gt;);\r\n\r\ng(\"hello\");   \/\/this should compile\r\ng(\"hello\"sv); \/\/this should not<\/pre>\n<p>The common way to implement this is using SFINAE. If we have a wrapper which looks like this<sup><a id=\"post-25026-footnote-ref-3\" href=\"#post-25026-footnote-3\">[2]<\/a><\/sup>:<\/p>\n<pre class=\"lang:default decode:true\">template&lt;class T&gt;\r\nstruct wrapper {\r\n  template &lt;class U&gt;\r\n  wrapper(U const&amp; u) : t_(u) {}\r\n\r\n  T t_;\r\n};<\/pre>\n<p>Then we replace the single constructor with two overloads: one implicit constructor for when <code>U<\/code> is convertible to <code>T<\/code> and one explicit overload for when it is not:<\/p>\n<pre class=\"lang:default decode:true\">template&lt;class T&gt;\r\nstruct wrapper {\r\n  template&lt;class U, std::enable_if_t&lt;std::is_convertible_v&lt;U, T&gt;&gt;* = nullptr&gt;\r\n  wrapper(U const&amp; u) : t_(u) {}\r\n  \r\n  template&lt;class U, std::enable_if_t&lt;!std::is_convertible_v&lt;U, T&gt;&gt;* = nullptr&gt;\r\n  explicit wrapper(U const&amp; u) : t_(u) {}\r\n\r\n  T t_;\r\n};<\/pre>\n<p>This gives our type the desired behavior. However, it\u2019s not very satisfactory: we now need two overloads for what should really be one and we\u2019re using SFINAE to choose between them, which means we take hits on compile-time and code clarity.<code>explicit(bool)<\/code> solves both problems by allowing you to lift the convertibility condition into the <code>explicit<\/code> specifier:<\/p>\n<pre class=\"lang:c++ decode:true\">template&lt;class T&gt; \r\nstruct wrapper { \r\n  template&lt;class U&gt; \r\n  explicit(!std::is_convertible_v&lt;U, T&gt;) \r\n  wrapper(U const&amp; u) : t_(u) {} \r\n\r\n  T t_; \r\n};<\/pre>\n<p>Next time you need to make something conditionally explicit, use <code>explicit(bool)<\/code> for simpler code, faster compile times<sup><a id=\"post-25026-footnote-ref-4\" href=\"#post-25026-footnote-4\">[3]<\/a><\/sup>, and less code repetition.<\/p>\n<p><code>explicit(bool)<\/code> will be supported in MSVC v14.24<sup><a id=\"post-25026-footnote-ref-5\" href=\"#post-25026-footnote-5\">[4]<\/a><\/sup> (available in Visual Studio 2019 version 16.4), Clang 9, and GCC 9. We\u2019d love for you to <a href=\"https:\/\/visualstudio.microsoft.com\/vs\/\">download Visual Studio 2019<\/a> and give it a try. As always, we welcome your feedback. We can be reached via the comments below or via email (<a href=\"mailto:visualcpp@microsoft.com\">visualcpp@microsoft.com<\/a>). If you encounter problems with Visual Studio or MSVC, or have a suggestion for us, please let us know through <strong>Help &gt; Send Feedback &gt; Report A Problem \/ Provide a Suggestion<\/strong> in the product, or via <a href=\"https:\/\/developercommunity.visualstudio.com\/\">Developer Community<\/a>. You can also find us on Twitter (<a href=\"https:\/\/twitter.com\/visualc\">@VisualC<\/a>).<\/p>\n<ol>\n<li id=\"post-25026-footnote-2\">I know, implicit conversions are evil. There are some places where they make a big improvement to ergonomics though and leaving choices to users makes our generic types more widely applicable. <a href=\"#post-25026-footnote-ref-2\">\u2191<\/a><\/li>\n<li id=\"post-25026-footnote-3\"><code>std::forward<\/code> and such omitted for brevity. <a href=\"#post-25026-footnote-ref-3\">\u2191<\/a><\/li>\n<li id=\"post-25026-footnote-4\">I tested 500 template instantiations with Visual Studio 2019 version 16.2 and using <code>explicit(bool)<\/code> sped up the frontend by ~15% <a href=\"#post-25026-footnote-ref-4\">\u2191<\/a><\/li>\n<li id=\"post-25026-footnote-5\">The feature is supported in MSVC v14.22 (Visual Studio 2019 version 16.2) for builds with \/permissive-, but there are some issues for builds which do not use that flag. <a href=\"#post-25026-footnote-ref-5\">\u2191<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>explicit(bool) is a C++20 feature for simplifying the implementation of generic types and improving compile-time performance. In C++ it is common to write and use types which wrap objects of other types. std::pair and std::optional are two examples, but there are plenty of others in the standard library, Boost, and likely your own codebases. Following [&hellip;]<\/p>\n","protected":false},"author":706,"featured_media":25040,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[512],"tags":[],"class_list":["post-25034","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general-cpp-series"],"acf":[],"blog_post_summary":"<p>explicit(bool) is a C++20 feature for simplifying the implementation of generic types and improving compile-time performance. In C++ it is common to write and use types which wrap objects of other types. std::pair and std::optional are two examples, but there are plenty of others in the standard library, Boost, and likely your own codebases. Following [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/25034","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\/706"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=25034"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/25034\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/25040"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=25034"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=25034"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=25034"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}