admin管理员组文章数量:1410696
using the following code
template <typename T>
concept SomeConcept = requires(T t) {
{ t++ } -> std::convertible_to<T>;
};
The concept SomeConcept
ensures that the type T
has overloaded the operator++(int)
and the result type is convertible to T
. And std::convertible_to
takes 2 parameters the first is From
, and the second is To
.
So my question is, which parameter takes the result of the expression and why? and by that answer why is T
is passed as the other parameter and not the other way around?
please provide a suitable reference to backup the answer, preferably from the standard draft if possible.
Thanks in advance
using the following code
template <typename T>
concept SomeConcept = requires(T t) {
{ t++ } -> std::convertible_to<T>;
};
The concept SomeConcept
ensures that the type T
has overloaded the operator++(int)
and the result type is convertible to T
. And std::convertible_to
takes 2 parameters the first is From
, and the second is To
.
So my question is, which parameter takes the result of the expression and why? and by that answer why is T
is passed as the other parameter and not the other way around?
please provide a suitable reference to backup the answer, preferably from the standard draft if possible.
Thanks in advance
Share edited Mar 9 at 19:37 Ahmed AEK 19.8k3 gold badges17 silver badges42 bronze badges asked Mar 9 at 19:24 MuhammadMuhammad 1,6953 gold badges22 silver badges33 bronze badges3 Answers
Reset to default 5From cppreference:
In a type-constraint, a concept takes one less template argument than its parameter list demands, because the contextually deduced type is implicitly used as the first argument of the concept.
template<class T, class U> concept Derived = std::is_base_of<U, T>::value; template<Derived<Base> T> void f(T); // T is constrained by Derived<T, Base>
So, even though std::convertible_to
takes two template parameters, the deduced type will be used as the first, which is the From
parameter in your case.
The kind of requirement here:
{ t++ } -> std::convertible_to<T>;
is called a compound-requirement. Those are defined in [expr.prim.reqpound], which tells us two things:
- that
std::convertible_to<T>
is a type-constraint — those are explained in `[temp.param] - that the "immediately-declared constraint" is
decltype((E))
.
The example that follows makes it clear what it means:
Given concepts
C
andD
,requires { { E1 } -> C; { E2 } -> D<A1, ..., An>;
is equivalent to
requires { E1; requires C<decltype((E1))>; E2; requires D<decltype((E2)), A1, ..., An>; }
Note the double parens: it's decltype((E))
, not decltype(E)
.
That is, while convertible_to
is a binary concept and it looks like we're only providing one type to it, in reality we're expressing:
template <typename T>
concept SomeConcept = requires(T t) {
t++;
requires std::convertible_to<decltype((t++)), T>;
};
I'll try to explain this.
In the expression { t++ } -> std::convertible_to<T>
, the result type of t++
becomes the From
parameter of std::convertible_to
, while T
is the To
parameter.
This is because std::convertible_to<From, To>
checks if From
can be converted to To
. In our case, we want to verify that the result of the postfix increment operation (which is typically a temporary object containing the original value) can be converted back to the type T
.
The standard concept std::convertible_to is defined as:
template<typename From, typename To>
concept convertible_to =
is_convertible_v<From, To> &&
requires { static_cast<To>(declval<From>()); };
So when we write { t++ } -> std::convertible_to<T>
, we're effectively saying "the result of t++
must be convertible to T
", which is exactly what we want to check for a well-behaved postfix increment operator.
本文标签: corder of passing parameters to templates in conceptsStack Overflow
版权声明:本文标题:c++ - order of passing parameters to templates in concepts - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744862006a2629126.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论