Sep 5, 2022

[C++][Concept] Techniques

Referernce:
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.