https://www.foonathan.net/2021/07/concepts-structural-nominal/
https://en.wikipedia.org/wiki/Structural_type_system
https://en.wikipedia.org/wiki/Nominal_type_system
This note extract the technique mentioned in Nathan's article for future quick reference.
Read https://vsdmars.blogspot.com/2022/03/c20-concepts-wrap-up.html first to have a good understanding about C++20 concept and how it works.
Go uses Interface to forge the concept of traits;
C++ relies on compile time thus using existing predicates to check for well-formed syntax.
std concepts
Techniques
Technique 1
Create a concept to check Type's internal typedef; iff defined does this type works as we expected.
// concept definition ===//
template <typename T>
concept my_concept
= requires { typename T::my_concept_tag; }
&& …;
//=== concept modelling ===//
struct my_type_modelling_the_concept
{
using my_concept_tag = void; // Doesn't matter.
};
In std e.g. we have std::range::enable_view variable template;thus we could explicit specialize it to enable 'view'' trait.
e.g.
namespace std
{
// Tell the compiler that your view is a view.
template <>
constexpr bool enable_view<my_namespace::MyViewType> = true;
}
Consider above code is too verbose, we could simply inherit
std::range::view_base to enable the 'view' trait' This is due to in std we have enable_view defined as:
namespace std
{
struct view_base
{};
// By default, a type is a view iff it inherits from view_base.
template <typename T>
constexpr bool enable_view = std::is_base_of_v<view_base, T>;
}
Technique 2
This technique is basically the previous I just mentioned;
i.e. using inheritance type check.
//=== concept definition ===//
struct my_concept_base {};
template <typename T>
constexpr bool enable_my_concept
= std::is_base_of_v<my_concept_base, T>;
template <typename T>
concept my_concept = enable_my_concept<T>
&& requires (T obj) { … };
//=== concept modelling ===//
struct my_type_modelling_the_concept : my_concept_base
{
…
};
Technique 3
Opt-out a trait with specialize concept:
namespace std
{
// MyLinkedList has O(n) size.
template <typename T>
constexpr bool std::ranges::disable_sized_range<MyLinkedList<T>> = true;
}
Opt-out a trait with variable template:
template <typename T>
constexpr bool disable_my_concept = false;
template <typename T>
concept my_concept = !disable_my_concept<T>
&& requires (T obj) { … };
We can use the same inheritance trick to opt-out a trait but that is counter-intuitive.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.