I want to abstract type interfaces and I am having a hard time to decide between the two C++ means of concepts and type_traits. Consider the follow scenario:
template <typename T>
int foo(const T& t) { return t.size() + t.size(); }
The type T is requested to provide int T::size() const. For creating better error messages, increasing usability for user-defined types of the client and giving him a well-defined list of what an acceptable type must be capable of, a concept can be introduced:
template <typename T>
concept SizeHaving = requires(T t) {
    t.size();
}
template <SizeHaving T>
int foo(const T& t) { return t.size() + t.size(); }
But what if a client type in principle could fulfill the concept, but technically doesn't (and cannot be changed, as it may be part of a third-party library)? A type_trait could help out:
struct Special {
   int Dimension() const; // logically identical to size(), but a different name
};
template <typename T>
struct Type_traits {
    static int size(const T& t) { return t.size(); }
};
template <> // user can provide the specialization for the custom type
struct Type_traits<Special> {
    static int size(const Special& c) { return c.Dimension(); }
};
template <typename T>
int foo(const T& t) {
    return Type_traits<T>::size(t) + Type_traits<T>::size(t);
}
If the standard implementation of Type_trait does not suit for a custom type (and no specialization is provided), there will be again rather unfortunate error messages. How can I get concepts into the play?
What I've tried is
template <typename T>
concept SizeHaving = requires(T t) {
    Type_traits<T>::size(t);
}
but the expression constraint will be technically satisfied for any type, whether Type_traits<T>::size() can be explicitly instantiated or not, rendering this concept useless. What can I do?
You might also constraint your traits:
template <typename T>
concept SizeHaving = requires(const T& t) {
    t.size(t);
};
template <typename T>
struct Type_traits
{
    auto size(const T& t) requires(SizeHaving<T>) { return t.size(); }
};
template <typename T>
concept TraitSizeHaving = requires(T t) {
    Type_traits<T>::size(t);
};
template <TraitSizeHaving T>
int foo(const T& t) {
    return Type_traits<T>::size(t) + Type_traits<T>::size(t);
}
And then specialize for your custom type:
struct Special {
   int Dimension() const; // logically identical to size(), but a different name
};
template <> // user can provide the specialization for the custom type
struct Type_traits<Special> {
    static int size(const Special& c) { return c.Dimension(); }
};
Demo.
Note: requires(SizeHaving<T>) should be done on member, and not the class to allow specialization of the class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With