Как ограничить шаблон класса, отключив аргумент типа самой специализации, и почему это не работает?

Возможно ли в настоящее время ограничить шаблон класса, который отклоняет аргумент типа, который является специализацией самого шаблона класса, без использования static_assert?

Поскольку я не могу использовать выражение requires, чтобы проверить, является ли оно допустимым именем типа, мне нужно создать валидатор создания экземпляра шаблона класса, который проверяет, является ли переданный шаблон класса допустимым с аргументами шаблона:

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...>();

Так как не удалось static_assert выдает серьезную ошибку, как эта:

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>>);

Второе статическое утверждение точно не скомпилируется, пока я не удалю это !, которое возвращает true, чего я не ожидал.

Что я хочу, так это отключить ошибку и заменить static_assert, чтобы:

static_assert(valid_instantiation<Hello, int>);
static_assert(!valid_instantiation<Hello, Hello<int>>);

может быть действительным.

Для первого статического утверждения создание экземпляра Hello<int> принимается просто отлично, в то время как второе статическое утверждение, создание экземпляра Hello<Hello<int>>, должно быть отклонено, потому что переданный аргумент шаблона является созданием экземпляра самого шаблона класса, но я не знаю, какие ограничения я буду использовать для их достижения.

Ничего страшного, если это невозможно сделать так или иначе.

Что именно вы считаете дружественным к SFINAE? Здесь не показана функция, а SFINAE для типов на самом деле нестандартен.

fabian 06.05.2022 17:53
static_assert(!requires { typename Hello<Hello<int>>; }); Это не сработает так или иначе.
康桓瑋 06.05.2022 17:54

"Я хочу иметь SFINAE-дружественную версию." Не совсем понятно, что вы здесь хотите. Вам нужна концепция, которая отфильтровывает такие вещи, чтобы вы могли ограничить это каким-то другим шаблоном? То есть может ли пользователь использовать Hello<Hello<T>> в определенных обстоятельствах, или вы всегда хотите, чтобы это не работало?

Nicol Bolas 06.05.2022 18:32

а если кто-то унаследует твое? struct B:Hello<A>;Hello<B>;?. На самом деле я не понимаю, как нужно ограничение, которое вы предлагаете.

apple apple 06.05.2022 18:36

Я голосую за то, чтобы закрыть этот вопрос, потому что: текущий код не демонстрирует идею (утверждение в любом случае не зависит от T).

apple apple 06.05.2022 18:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
5
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Не уверен, что это то, что вы хотите, но

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
{
// ...
};

Не уверен, как вы хотите SFINAE или протестировать его (черта кажется эквивалентной), поскольку Hello<Hello<T>> не может существовать.

Демо

Другие вопросы по теме