Концепция использования оператора внутри класса

У меня есть такой класс:

struct FooImpl {
public:
  using Bar = int;
};

Я хотел бы заявить, что FooImpl::Bar — это int через концепцию.

Это делает работу:

template<typename Foo>
concept FooConcept = requires(Foo foo) {
  { std::vector<typename Foo::Bar>() } -> std::same_as<std::vector<int>>;
};
 
static_assert(FooConcept<FooImpl>);

Есть ли более элегантный способ сделать это? Я пытался:

  { (typename Foo::Bar)() } -> std::same_as<int>;

Но компилятору это не нравится.

@Ranoiaetep: это не самое неприятное, поскольку спецификатор имени типа не может быть декларатором. Просто вы не можете приводить скобки в стиле C, содержащие не одно выражение.

Davis Herring 26.11.2022 02:56

@DavisHerring Вы правы, отредактировал мой ответ

Ranoiaetep 26.11.2022 03:12
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Во-первых, причина, по которой { (typename Foo::Bar)() } -> std::same_as<int>; не работает, заключается в том, что самый неприятный синтаксический анализ typename-specifier не может быть декларатором и не может использоваться в круглых скобках C-style. * Чтобы заставить его работать, вы должны использовать вместо этого инициализируйте фигурную скобку:

template<typename Foo>
concept FooConcept = requires(Foo foo) {
    { typename Foo::Bar{} } -> std::same_as<int>;
};

* Corrected by @DavisHerring from the comment


Во-вторых, если единственное ограничение, которое у вас есть, — убедиться, что определенный вложенный тип совпадает с другим, вы можете просто использовать std::same_as:

template<typename Foo>
concept FooConcept = std::same_as<typename Foo::Bar, int>;

Наконец, некоторые термины:

Я хотел бы заявить, что FooImpl::Bar — это int через концепцию.

Объявление FooImpl::Bar как int уже было сделано оператором использования (using Bar = int). Вероятно, вы имели в виду:

  • Вы хотите объявить концепцию для типа T, который требует, чтобы T::Bar был int.

Или:

  • Вы хотите ограничить тип T, который T::Bar является int, посредством концепции.

Спасибо, скобка init - это то, что я искал. У меня действительно есть другие ограничения в моем реальном случае использования, поэтому я искал решение, используя requires.

dshin 26.11.2022 03:00

Хотя моя терминология, по общему признанию, небрежна, ваши предложенные улучшения ссылаются на Foo, прежде чем объявить об этом.

dshin 26.11.2022 03:02

@dshin Разве Foo не было имени типа шаблона в вашем коде? Это равносильно замене Foo на T.

Ranoiaetep 26.11.2022 03:06

Да, я просто хочу сказать, что предложение, которое вы предложили заменить, происходит до того, как введено имя типа шаблона Foo.

dshin 26.11.2022 03:51

@dshin Отредактировал мой ответ, чтобы использовать «Foo» -> «тип T», чтобы лучше понять контекст

Ranoiaetep 26.11.2022 03:54

Конечно, это работает. С другой стороны, эти заменяющие предложения лишены какой-либо ссылки на FooImpl. Это своего рода помещает фрагмент кода FooImpl на остров с единственной последующей ссылкой на него в оставшейся части ответа в виде утверждения static_assert. Это, в свою очередь, требует поставить ваше предложение в начале, затем концепт Foo, а затем FooImpl. Это лучший способ написать вопрос?

dshin 26.11.2022 04:01

@dshin Я согласен, что это помещает фрагмент кода FooImpl на остров. Тем не менее, я считаю, что вопрос был о том, как написать заявление о концепции/требовании, верно? Помните, что концепции — это просто функции для метапрограммирования, оператор require — это их определение, а FooImpl в вашем случае — это аргумент, передаваемый этой функции метапрограммирования. Итак, FooImpl на самом деле является объектом, а не субъектом в этом вопросе. Кто-то должен вывести аналогичный ответ даже без определения FooImpl.

Ranoiaetep 26.11.2022 04:18

@dshin В том же смысле, что если бы я спросил, как написать bool func(int n), значение i, которое я хотел бы передать функции, скорее всего, не важно. Важно то, что делает func, и наличие i с разными значениями не должно изменить способ определения func.

Ranoiaetep 26.11.2022 04:24

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