Home > Back-end >  How to write a Character type concept?
How to write a Character type concept?

Time:08-11

The standard library doesn't seem to provide a concept for character types yet. Similar to e.g. std::integral, I want a concept that is suitable for character types (such as char, wchar_t, char32_t, etc.). How should one write a proper concept for this purpose?

Something similar to this could help:

template <typename T>
concept Character = std::integral<T> && sizeof( T ) <= 4;

But I feel like the above is not sufficient. I guess it should have more constraints.

CodePudding user response:

Since std::char_traits doesn't forbid instantiation for types other than character types, I believe you have to list it all by yourself.

template <typename T>
concept Character = 
    std::same_as<T, char> ||
    std::same_as<T, signed char> ||
    std::same_as<T, unsigned char> ||
    std::same_as<T, wchar_t> ||
    std::same_as<T, char8_t> ||
    std::same_as<T, char16_t> ||
    std::same_as<T, char32_t>;

CodePudding user response:

template< class T >
concept Character = 
    /* true if T is same as the listed char types below
     * do not forget that e.g. same_as<char, T> is true only
     * when T is char and not char&, unsigned char, const char
     * or any combination (cvref),
     * therefore we only remove the const volatile specifiers
     * but not the reference (like in is_integral) */
    std::same_as< char, std::remove_cv_t<T> > ||
    /* do for each char type, 
     * see: https://en.cppreference.com/w/cpp/language/types#Character_types */;

Based on the discussion below:

I would say if you introduce a character trait, it would be a good idea to do it like the standard does for e.g. integral types. CV-qualified, signed or unsigned. But not a reference to an integral type, like pointer, which is not that specific type that it points to.

Therefore my suggestion would be a proper (standard conform) type trait for all character types (signed/unsigned, cv-qualified).

To restrict the type of a member variable, there are other methods to achieve that, either through a type constraint (requires) or an assertion (static_assert) or by simply removing the cv-qualifiers.

e.g.

template <Character C>
requires !(std::is_const_v<C> || std::is_volatile_v<C>)
class Foo { static C var = '$'; };

or

template <Character C>
class Foo { 
    static_assert(
        !(std::is_const_v<C> || std::is_volatile_v<C>),
        "No cv types allowed."
    );
    static C var = '$'; 
};

or

template <Character C>
class Foo { 
    using char_type = std::remove_cv_t<C>;
    static char_type var = '$'; 
};
  • Related