diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2022-09-28 22:10:29 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2022-09-28 22:10:29 +0200 |
commit | 99c1f88e7396ee87a812f8d114aac8d903eb7afb (patch) | |
tree | 7352e9d3e131af424be5b2a941860568c9e6db3f | |
parent | 47218d271f20b39610d5f63b3bc7dfc86642bdba (diff) | |
download | notes-99c1f88e7396ee87a812f8d114aac8d903eb7afb.tar.gz notes-99c1f88e7396ee87a812f8d114aac8d903eb7afb.zip |
c++: pre c++20 concept example
-rw-r--r-- | src/development/c++.md | 26 | ||||
-rw-r--r-- | src/development/c++/concepts-11.cc | 53 |
2 files changed, 79 insertions, 0 deletions
diff --git a/src/development/c++.md b/src/development/c++.md index b42a263..1cc4003 100644 --- a/src/development/c++.md +++ b/src/development/c++.md @@ -32,9 +32,35 @@ available traits an operation can have: ```cpp {{#include c++/meta2.cc:3:}} +``` + +## Example: Concepts pre c++20 + +Prior to c++20's concepts, `SFINAE` and `std::void_t` can be leveraged to build +something similar allowing to define an interface (aka trait) for a template +parameter. +```cpp +{{#include c++/concepts-11.cc:3:}} ``` +The main mechanic can be explained with the following reduced example. If one +of the `decltype(std:declval<T>...` expressions is ill-formed, the template +specialization for `is_valid` will be removed from the candidate set due to +[SFINAE][sfinae]. +```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 {}; +``` +> `std::declval<T>()` creates an instance of type T in an unevaluated context. + + [gist-strict-asliasing]: https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 [parameter-pack]: https://en.cppreference.com/w/cpp/language/parameter_pack [enable-if]: https://en.cppreference.com/w/cpp/types/enable_if diff --git a/src/development/c++/concepts-11.cc b/src/development/c++/concepts-11.cc new file mode 100644 index 0000000..888ff4d --- /dev/null +++ b/src/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>>, ""); +} |