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 = '$';
};