Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to constrain class template by disabling type argument of specialization itself, and why does(n't) it work?

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.

like image 722
Desmond Gold Avatar asked Nov 14 '25 17:11

Desmond Gold


1 Answers

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

like image 59
Jarod42 Avatar answered Nov 17 '25 08:11

Jarod42



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!