Возможно ли в настоящее время ограничить шаблон класса, который отклоняет аргумент типа, который является специализацией самого шаблона класса, без использования 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>>
, должно быть отклонено, потому что переданный аргумент шаблона является созданием экземпляра самого шаблона класса, но я не знаю, какие ограничения я буду использовать для их достижения.
Ничего страшного, если это невозможно сделать так или иначе.
static_assert(!requires { typename Hello<Hello<int>>; });
Это не сработает так или иначе.
"Я хочу иметь SFINAE-дружественную версию." Не совсем понятно, что вы здесь хотите. Вам нужна концепция, которая отфильтровывает такие вещи, чтобы вы могли ограничить это каким-то другим шаблоном? То есть может ли пользователь использовать Hello<Hello<T>>
в определенных обстоятельствах, или вы всегда хотите, чтобы это не работало?
а если кто-то унаследует твое? struct B:Hello<A>;
Hello<B>;
?. На самом деле я не понимаю, как нужно ограничение, которое вы предлагаете.
Я голосую за то, чтобы закрыть этот вопрос, потому что: текущий код не демонстрирует идею (утверждение в любом случае не зависит от T).
Не уверен, что это то, что вы хотите, но
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>>
не может существовать.
Что именно вы считаете дружественным к SFINAE? Здесь не показана функция, а SFINAE для типов на самом деле нестандартен.