Home > Back-end >  How to constrain class template by disabling type argument of specialization itself, and why does(n&
How to constrain class template by disabling type argument of specialization itself, and why does(n&

Time:05-07

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.

Demo

  • Related