Could type traits be restricted to not accept other type traits as arguments?
Well, assuming you always need a ::type
as argument where possible, here's a quick workaround:
template<class T> concept HasType = requires { typename T::type; };
template<class T> concept HasNoType = !HasType<T>;
template<HasNoType T> using remove_cv = std::remove_cv<T>;
template<HasNoType T> using remove_cv_t = typename remove_cv<T>::type;
Other than patching STL headers, or subclassing STL types (which is not always permitted), you cannot redefine what was predefined.
your restriction is not based on semantics of types(aka has ++ and *) but on the fact that types belong to a huge set of types
Whatever goes, you'll need a predicate to specify this set (operator ∊S
for a given S). For instance has ++
is as good a predicate as any other.
The predicate can be refined with more levels of indirections and some boilerplate, say
template<class T> struct not_a_type_trait =
std::integral_constant<bool, HasNoType<T>> {};
template<class T> inline constexpr not_a_type_trait_v = not_a_type_trait<T>::value;
template<class T> concept NotATrait = not_a_type_trait_v<T>;
struct AnArg { using type = void; };
template<> struct not_a_type_trait<AnArg>: std::true_type {};
// now can be an arg to remove_cv
Or, here in this particular case, you can simply blacklist all the STL's traits, but that would be a really huge predicate to be updated with each Standard revision.