diff options
author | johannst <johannst@users.noreply.github.com> | 2022-09-30 10:58:40 +0000 |
---|---|---|
committer | johannst <johannst@users.noreply.github.com> | 2022-09-30 10:58:40 +0000 |
commit | fa7eb205d5f18b72c1e04a4229d171a15040bdea (patch) | |
tree | 2b9965406fb65fdc44ec3eddd2924e5be3f06c8e /development | |
parent | 0c31b8e434d634c81479bf396c752d1baaff7603 (diff) | |
download | notes-fa7eb205d5f18b72c1e04a4229d171a15040bdea.tar.gz notes-fa7eb205d5f18b72c1e04a4229d171a15040bdea.zip |
deploy: b6f25b16f1f23b0169e8f076e79ee4964b81db99
Diffstat (limited to 'development')
-rw-r--r-- | development/c++.html | 71 | ||||
-rw-r--r-- | development/c++/concepts-11.cc | 53 |
2 files changed, 124 insertions, 0 deletions
diff --git a/development/c++.html b/development/c++.html index d5f9979..80d8ab5 100644 --- a/development/c++.html +++ b/development/c++.html @@ -296,8 +296,79 @@ int main() { return 0; } +</code></pre> +<h2 id="example-concepts-pre-c20"><a class="header" href="#example-concepts-pre-c20">Example: Concepts pre c++20</a></h2> +<p>Prior to c++20's concepts, <code>SFINAE</code> and <code>std::void_t</code> can be leveraged to build +something similar allowing to define an interface (aka trait) for a template +parameter.</p> +<pre><code class="language-cpp"> +template<typename T, template<typename> class Checker, typename = void> +struct is_valid : std::false_type {}; + +template<typename T, template<typename> class Checker> +struct is_valid<T, Checker, std::void_t<Checker<T>>> : std::true_type {}; + +template<typename T, template<typename> class Checker> +static constexpr bool is_valid_v = is_valid<T, Checker>::value; + +// ----------------------------------------------------------------------------- + +template<typename T, typename R, template<typename> class Checker, typename = void> +struct is_valid_with_ret : std::false_type {}; +template<typename T, typename R, template<typename> class Checker> +struct is_valid_with_ret<T, R, Checker, std::void_t<Checker<T>>> : std::is_same<R, Checker<T>> {}; + +template<typename T, typename R, template<typename> class Checker> +static constexpr bool is_valid_with_ret_v = is_valid_with_ret<T, R, Checker>::value; + +// ----------------------------------------------------------------------------- + +template<typename T> +struct is_entry { + template<typename TT> + using init = decltype(std::declval<TT>().init()); + template<typename TT> + using tag = decltype(std::declval<TT>().tag()); + template<typename TT> + using val = decltype(std::declval<TT>().val()); + + static constexpr bool value = is_valid_v<T, init> && + is_valid_with_ret_v<T, int, tag> && + is_valid_with_ret_v<T, typename T::Type, val>; +}; + +template<typename T> +static constexpr bool is_entry_v = is_entry<T>::value; + +template<typename E> +struct Entry { + using Type = E; + void init(); + int tag() const; + E val() const; +}; + +int main() { + static_assert(is_entry_v<Entry<bool>>, ""); +} +</code></pre> +<p>The main mechanic can be explained with the following reduced example. If one +of the <code>decltype(std:declval<T>...</code> expressions is ill-formed, the template +specialization for <code>is_valid</code> will be removed from the candidate set due to +<a href="https://en.cppreference.com/w/cpp/language/sfinae">SFINAE</a>.</p> +<pre><code class="language-cpp">template<typename T, typename = void> +struct is_valid : std::false_type {}; + +template<typename T> +struct is_valid<T, std::void_t< + decltype(std::declval<T>().some_fun1()), + decltype(std::declval<T>().some_fun2()) + >> : std::true_type {}; </code></pre> +<blockquote> +<p><code>std::declval<T>()</code> creates an instance of type T in an unevaluated context.</p> +</blockquote> </main> diff --git a/development/c++/concepts-11.cc b/development/c++/concepts-11.cc new file mode 100644 index 0000000..888ff4d --- /dev/null +++ b/development/c++/concepts-11.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2022 johannst +#include <type_traits> + +template<typename T, template<typename> class Checker, typename = void> +struct is_valid : std::false_type {}; + +template<typename T, template<typename> class Checker> +struct is_valid<T, Checker, std::void_t<Checker<T>>> : std::true_type {}; + +template<typename T, template<typename> class Checker> +static constexpr bool is_valid_v = is_valid<T, Checker>::value; + +// ----------------------------------------------------------------------------- + +template<typename T, typename R, template<typename> class Checker, typename = void> +struct is_valid_with_ret : std::false_type {}; + +template<typename T, typename R, template<typename> class Checker> +struct is_valid_with_ret<T, R, Checker, std::void_t<Checker<T>>> : std::is_same<R, Checker<T>> {}; + +template<typename T, typename R, template<typename> class Checker> +static constexpr bool is_valid_with_ret_v = is_valid_with_ret<T, R, Checker>::value; + +// ----------------------------------------------------------------------------- + +template<typename T> +struct is_entry { + template<typename TT> + using init = decltype(std::declval<TT>().init()); + template<typename TT> + using tag = decltype(std::declval<TT>().tag()); + template<typename TT> + using val = decltype(std::declval<TT>().val()); + + static constexpr bool value = is_valid_v<T, init> && + is_valid_with_ret_v<T, int, tag> && + is_valid_with_ret_v<T, typename T::Type, val>; +}; + +template<typename T> +static constexpr bool is_entry_v = is_entry<T>::value; + +template<typename E> +struct Entry { + using Type = E; + void init(); + int tag() const; + E val() const; +}; + +int main() { + static_assert(is_entry_v<Entry<bool>>, ""); +} |