У меня есть такой класс:
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>;
Но компилятору это не нравится.
@DavisHerring Вы правы, отредактировал мой ответ
Во-первых, причина, по которой { (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
.
Хотя моя терминология, по общему признанию, небрежна, ваши предложенные улучшения ссылаются на Foo
, прежде чем объявить об этом.
@dshin Разве Foo
не было имени типа шаблона в вашем коде? Это равносильно замене Foo
на T
.
Да, я просто хочу сказать, что предложение, которое вы предложили заменить, происходит до того, как введено имя типа шаблона Foo
.
@dshin Отредактировал мой ответ, чтобы использовать «Foo
» -> «тип T
», чтобы лучше понять контекст
Конечно, это работает. С другой стороны, эти заменяющие предложения лишены какой-либо ссылки на FooImpl
. Это своего рода помещает фрагмент кода FooImpl
на остров с единственной последующей ссылкой на него в оставшейся части ответа в виде утверждения static_assert
. Это, в свою очередь, требует поставить ваше предложение в начале, затем концепт Foo
, а затем FooImpl
. Это лучший способ написать вопрос?
@dshin Я согласен, что это помещает фрагмент кода FooImpl
на остров. Тем не менее, я считаю, что вопрос был о том, как написать заявление о концепции/требовании, верно? Помните, что концепции — это просто функции для метапрограммирования, оператор require — это их определение, а FooImpl
в вашем случае — это аргумент, передаваемый этой функции метапрограммирования. Итак, FooImpl
на самом деле является объектом, а не субъектом в этом вопросе. Кто-то должен вывести аналогичный ответ даже без определения FooImpl
.
@dshin В том же смысле, что если бы я спросил, как написать bool func(int n)
, значение i
, которое я хотел бы передать функции, скорее всего, не важно. Важно то, что делает func
, и наличие i
с разными значениями не должно изменить способ определения func
.
@Ranoiaetep: это не самое неприятное, поскольку спецификатор имени типа не может быть декларатором. Просто вы не можете приводить скобки в стиле C, содержащие не одно выражение.