{"id":4129,"date":"2019-02-15T20:49:41","date_gmt":"2019-02-15T19:49:41","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=4129"},"modified":"2019-02-16T11:43:37","modified_gmt":"2019-02-16T10:43:37","slug":"c-guns-class-template-specialization-with-concepts","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=4129","title":{"rendered":"C++ Guns: class template specialization with concepts aka C++20 std::ranges::value_type"},"content":{"rendered":"<p>You can create a constrain for a class. And another constrain for the same class. Isn't this crazy stuff?<\/p>\n<p>With this we can build something like an identity function for types, like <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/types\/type_identity\">std::type_identity<\/a>, for value_type. It's something like the C++17 non-member functions <em>size()<\/em> and <em>empty()<\/em>. Why must value_type be a member? It can be a non-member trait.<\/p>\n<p>It turns out, there is already this functionality in C++ 20 ranges TS in <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/experimental\/ranges\/iterator\/value_type\">std::experimental::ranges::value_type<\/a>. It's really hard to catch up... but implemented it for you. And users may specialize value_type I also put my part for arithmetic types here.<\/p>\n<p>This is part of ACPL <a href=\"https:\/\/sourceforge.net\/p\/acpl\/code\/ci\/master\/tree\/acpl\/acpllib\/include\/core\/util\/functional.hpp\">functional.hpp<\/a> file.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/\/ Primary template is an empty struct.\r\n\/\/\/ \\note this is in C++20 ranges now except for the arithmetic types overload \r\n\/\/\/ https:\/\/en.cppreference.com\/w\/cpp\/experimental\/ranges\/iterator\/value_type\r\ntemplate&lt;class I&gt;\r\nstruct value_type { };\r\n\r\n\/\/\/ Specialization for pointers.\r\n\/\/\/ If T is an object type, provides a member type type equal to std::remove_cv_t&lt;T&gt;.\r\n\/\/\/  Otherwise, there is no member type.\r\ntemplate&lt;class T&gt;\r\nstruct value_type&lt;T*&gt; {\r\n  using type = std::remove_cv_t&lt;T&gt;;\r\n};\r\n\r\n\/\/\/ Specialization for array types.\r\ntemplate&lt;class I&gt;\r\n  requires(std::is_array&lt;I&gt;::value)\r\nstruct value_type&lt;I&gt; : value_type&lt;std::decay_t&lt;I&gt;&gt; { };\r\n\r\n\/\/\/ Specialization for const-qualified types.\r\ntemplate&lt;class T&gt;\r\nstruct value_type&lt;const T&gt; : value_type&lt;std::decay_t&lt;T&gt;&gt; { };\r\n\r\n\/\/\/ Specialization for types that define a public and accessible member type value_type.\r\n\/\/\/ If T::value_type is an object type, provides a member type type equal to T::value_type.\r\n\/\/\/ Otherwise, there is no member type.\r\n\/\/\/ \\todo requires requires\r\ntemplate&lt;class T&gt;\r\n  requires requires{ typename T::value_type; }\r\nstruct value_type&lt;T&gt; {\r\n  using type = typename T::value_type;\r\n};\r\n\r\n\/\/\/ Specialization for types that define a public and accessible member type element_type.\r\n\/\/\/ (e.g., std::shared_ptr).\r\n\/\/\/ If T::element_type is an object type, provides a member type type equal to std::remove_cv_t&lt;typename T::element_type&gt;.\r\n\/\/\/ Otherwise, there is no member type.\r\ntemplate&lt;class T&gt;\r\n  requires requires{ typename T::element_type; }\r\nstruct value_type&lt;T&gt; {\r\n    using type = typename T::element_type;\r\n};\r\n\r\n\/\/\/ Helper alias template\r\ntemplate&lt;class T&gt;\r\nusing value_type_t = typename value_type&lt;T&gt;::type;\r\n\r\n\/\/\/ ACPL specialization for arithmetic types\r\ntemplate&lt;class T&gt;\r\n  requires(std::is_arithmetic_v&lt;T&gt;)\r\nstruct value_type&lt;T&gt; {\r\n    using type = T;\r\n};\r\n\r\n    \/\/ Specialization for pointers.\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;int*&gt;&gt;);\r\n    \/\/ Specialization for array types.\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;int&#x5B;]&gt;&gt;);\r\n    \/\/ Specialization for const-qualified types.\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;const int*&gt;&gt;);\r\n    \/\/ Specialization for types that define a public and accessible member type value_type.\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;std::array&lt;int,1&gt;&gt;&gt;);\r\n    \/\/ Specialization for types that define a public and accessible member type element_type.\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;std::unique_ptr&lt;int&gt;&gt;&gt;);\r\n\r\n    \/\/ ACPL specialization for arithmetic types\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;int&gt;&gt;);\r\n    static_assert(std::is_same_v&lt;int, acpl::value_type_t&lt;const int&gt;&gt;);\r\n<\/pre>\n<p>For the record, this is my first try:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntemplate&lt;typename T&gt;\r\nstruct value_type {\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nrequires(std::is_scalar_v&lt;T&gt;)\r\nstruct value_type&lt;T&gt; {\r\n    using type = T;\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nrequires(not std::is_scalar_v&lt;T&gt;)\r\nstruct value_type&lt;T&gt; {\r\n    using type = typename T::value_type;\r\n};\r\n\r\ntemplate&lt;typename T&gt;\r\nusing value_type_t = typename value_type&lt;T&gt;::type;\r\n\r\nstatic_assert(std::is_same_v&lt;int, value_type_t&lt;int&gt;&gt; );\r\nstatic_assert(std::is_same_v&lt;int, value_type_t&lt;std::vector&lt;int&gt;&gt;&gt; );\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>You can create a constrain for a class. And another constrain for the same class. Isn't this crazy stuff? With this we can build something like an identity function for types, like std::type_identity, for value_type. It's something like the C++17 non-member functions size() and empty(). Why must value_type be a member? It can be a [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-4129","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4129"}],"version-history":[{"count":6,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4129\/revisions"}],"predecessor-version":[{"id":4135,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/4129\/revisions\/4135"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4129"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}