You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A few fundamental problems make it hard or impossible to constrain generic code that uses UFCS.
Due to the order independence of function bodies,
the use of the UFCS macro in the signature
causes the closure type of the definition to mismatch that of the declaration.
UFCS as a Cpp1 feature would solve this issue.
[ Example: See https://cpp2.godbolt.org/z/ndhdTfchj.
In this case, I think the onus can be on the author of the generic component.
They can choose not use the UFCS syntax. -- end example ]
#define REQUIRES_EXPRESSION(...) requires { __VA_ARGS__ }
#define COMPOUND_REQUIREMENT(E, C) { E } -> C;
count_if: @struct <F: type> type =
{
public pred: F;
is_valid: <
I: type,
S: type
>(
in this,
copy first: I,
copy last: S
) -> move _ ==
{
return std::bool_constant<REQUIRES_EXPRESSION(COMPOUND_REQUIREMENT(first*.pred(), std::convertible_to<bool>))>();
_ = first;
_ = last;
}
operator(): <
I: type,
S: type
>(
in this,
copy first: I,
copy last: S
) -> move std::enable_if_t<std::type_identity_t<decltype(is_valid(first, last))>::value, std::iter_difference_t<I>> requires (std::sentinel_for<S, I>)
/* (GCC) `error: no declaration matches`...
* (Clang) After dropping `_NONLOCAL` from the UFCS macro (<https://cpp2.godbolt.org/z/ThMfKKbE4>):
* `error: out-of-line definition of 'operator()' does not match any declaration in 'count_if<F>'`.
* The closure type in the signature of the definition mismatches that of the declaration.
* We need a way to constraint with the UFCS call `first*.pred()`. */
// && REQUIRES_EXPRESSION(COMPOUND_REQUIREMENT(first*.pred(), std::convertible_to<bool>))
=
{
count: = std::iter_difference_t<I>(0);
while first != last
next first++
{
if !first*.pred()
{
continue;
}
count++;
}
return count;
}
operator(): <R: type>(
in this,
forward r: R
) -> move std::ranges::range_difference_t<R> =
{
return operator()(std::ranges::begin(r), std::ranges::end(r));
_ = r;
}
}
main: () = {
v := std::vector(3, 0);
assert((:count_if = :(_) -> _ == true)(v) == 3);
}
//=== Cpp2 type declarations ====================================================
#include"cpp2util.h"
#line 1 "/app/example.cpp2"
#line 4 "/app/example.cpp2"
template<typename F> classcount_if;
//=== Cpp2 type definitions and function declarations ===========================
#line 1 "/app/example.cpp2"
#defineREQUIRES_EXPRESSION(...) requires { __VA_ARGS__ }
#defineCOMPOUND_REQUIREMENT(E, C) { E } -> C;
#line 4 "/app/example.cpp2"
template<typename F> classcount_if
{
public: F pred;
public:template<
typename I,
typename S
> [[nodiscard]] constexprautois_valid(
I first,
S last
) const& -> auto;
#line 22 "/app/example.cpp2"
public:template<
typename I,
typename S
> [[nodiscard]] autooperator()(
I first,
S last
) const& -> std::enable_if_t<std::type_identity_t<decltype(is_valid(first, std::move(last)))>::value,std::iter_difference_t<I>>
CPP2_REQUIRES_ ((std::sentinel_for<S,I>))
#line 22 "/app/example.cpp2"
;
#line 30 "/app/example.cpp2"
/* (GCC) `error: no declaration matches`... (Clang) After dropping `_NONLOCAL` from the UFCS macro (<https://cpp2.godbolt.org/z/ThMfKKbE4>): `error: out-of-line definition of 'operator()' does not match any declaration in 'count_if<F>'`. The closure type in the signature of the definition mismatches that of the declaration. We need a way to constraint with the UFCS call `first.pred()`. */// && REQUIRES_EXPRESSION(COMPOUND_REQUIREMENT(first*.pred(), std::convertible_to<bool>))
#line 51 "/app/example.cpp2"
public:template<typename R> [[nodiscard]] autooperator()(
R&& r
) const& -> std::ranges::range_difference_t<R>;
#line 59 "/app/example.cpp2"
};
automain() -> int;
//=== Cpp2 function definitions =================================================
#line 1 "/app/example.cpp2"
#line 8 "/app/example.cpp2"
template <typename F> template<
typename I,
typename S
> [[nodiscard]] constexprauto count_if<F>::is_valid(
I first,
S last
) const& -> auto
{
return std::bool_constant<REQUIRES_EXPRESSION(COMPOUND_REQUIREMENT(CPP2_UFCS(pred)((*cpp2::assert_not_null(first))), std::convertible_to<bool>))>();
static_cast<void>(std::move(first));
static_cast<void>(std::move(last));
}
template <typename F> template<
typename I,
typename S
> [[nodiscard]] auto count_if<F>::operator()(
I first,
S last
) const& -> std::enable_if_t<std::type_identity_t<decltype(is_valid(first, std::move(last)))>::value,std::iter_difference_t<I>>
requires ((std::sentinel_for<S,I>))
#line 37 "/app/example.cpp2"
{
auto count {std::iter_difference_t<I>(0)};
for( ; first != last;
++first )
{
if (!(CPP2_UFCS(pred)((*cpp2::assert_not_null(first)))))
{
continue;
}
++count;
}
return count;
}
template <typename F> template<typename R> [[nodiscard]] auto count_if<F>::operator()(
R&& r
) const& -> std::ranges::range_difference_t<R>
{
returnoperator()(std::ranges::begin(r), std::ranges::end(r));
static_cast<void>(CPP2_FORWARD(r));
}
#line 61 "/app/example.cpp2"
automain() -> int{
auto v {std::vector(3, 0)};
cpp2::Default.expects((count_if{[]([[maybe_unused]] autoconst& unnamed_param_1) -> auto { returntrue; }})(std::move(v)) == 3, "");
}
The text was updated successfully, but these errors were encountered:
Title: Can't constrain member function with UFCS on callable data member.
Description:
A few fundamental problems make it hard or impossible to constrain generic code that uses UFCS.
Due to the order independence of function bodies,
the use of the UFCS macro in the signature
causes the closure type of the definition to mismatch that of the declaration.
UFCS as a Cpp1 feature would solve this issue.
[ Example: See https://cpp2.godbolt.org/z/ndhdTfchj.
In this case, I think the onus can be on the author of the generic component.
They can choose not use the UFCS syntax. -- end example ]
The context of the function body
f: () x.f();
) #874), andusing
statements (a problem in Cpp1, too).The same expression in a
concept
orrequires
can have a different meaning.For example, these calls can call a non-member in a
concept
, but not here:In this case, the onus is on the author of the generic component.
Minimal reproducer (https://cpp2.godbolt.org/z/hz75Kaxhq):
Commands:
cppfront main.cpp2 clang++18 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -Werror=unused-result -Werror=unused-value -Werror=unused-parameter -Werror=unused-variable -I . main.cpp
Cpp2 lowered to Cpp1:
The text was updated successfully, but these errors were encountered: