Is it currently possible to constrain a class template that rejects type argument which is the specialization of the class template itself without using static_assert
?
Since I cannot use requires
expression to check if it is a valid typename, I have to create a class template instantiation validator that checks whether the class template passed is valid with template arguments:
template <template <typename...> typename Temp, typename... Ts>
requires requires { typename Temp<Ts...>; }
constexpr bool is_valid() { return true; }
template <template <typename...> typename, typename...>
constexpr bool is_valid() { return false; }
template <template <typename...> typename Temp, typename... Ts>
concept valid_instantiation = is_valid<Temp, Ts...>();
Since failed static_assert
emits a hard error, just like this one:
template <typename>
class Hello;
template <typename>
inline constexpr bool is_hello_v = false;
template <typename T>
inline constexpr bool is_hello_v<Hello<T>> = true;
template <typename T>
class Hello {
static_assert(!is_hello_v<T>);
};
static_assert(valid_instantiation<Hello, int>);
static_assert(!valid_instantiation<Hello, Hello<int>>);
The second static assertion sure didn't compile unless I remove that !
that returns true
which is not what I expected.
What I want to have is to silent the error and replace the static_assert
, so that:
static_assert(valid_instantiation<Hello, int>);
static_assert(!valid_instantiation<Hello, Hello<int>>);
can be valid.
For the first static assertion, the Hello<int>
instantiation is accepted just fine, while the second static assertion, Hello<Hello<int>>
instantiation should be rejected because the template argument passed is the instantiation of the class template itself but I have no knowledge what constraints I'll be using to achieve these.
It's ok if it is impossible to do so, or otherwise.
CodePudding user response:
Not sure it is what you want, but
template <typename T> struct is_Hello;
template <typename T> requires (!is_Hello<T>::value) class Hello;
template <typename T> struct is_Hello : std::false_type{};
template <typename T> struct is_Hello<Hello<T>> : std::true_type{};
template <typename T>
requires (!is_Hello<T>::value) // So Hello<Hello<T>> is not possible
class Hello
{
// ...
};
Not sure how you want to SFINAE or test it (the trait seems equivalent), as Hello<Hello<T>>
cannot exist.