-
Notifications
You must be signed in to change notification settings - Fork 261
[SUGGESTION] Add possibility of using lambda in is-statements (inspect and if statements) #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SUGGESTION] Add possibility of using lambda in is-statements (inspect and if statements) #90
Conversation
48dbcb3
to
aef3217
Compare
Ah... the change works in if statements but it is not working yet with |
On the last push I have added support for using |
c088908
to
4c87da8
Compare
848a996
to
cfa2b25
Compare
I have noticed that my other PRs regarding using Currently, I am not able to allow generic lambda use as I don't know how to write requires clause for lambda_wrapper that will match them. Now it matches types that matches: template <typename F, typename Capture = std::monostate>
requires (
requires { &F::operator(); }
)
struct lambda_wrapper; What is currently possible is visible here: #include <utility>
#include <tuple>
#include <iostream>
#include <vector>
#include <span>
constexpr auto less_then = [](int value) {
return cpp2::lambda_wrapper([](int x, int capture) { return x < capture;}, value);
};
constexpr auto in = [](auto min, auto max) {
return cpp2::lambda_wrapper([](int x, std::pair<int,int> capture) {
return std::get<0>(capture) <= x && x <= std::get<1>(capture);
}, std::pair(min,max));
};
constexpr auto empty = cpp2::lambda_wrapper([](std::span<const int> x){
return std::empty(x);
});
main: () -> int = {
i := 15;
if i is less_then(20) {
std::cout << "less than 20" << std::endl;
}
if i is in(10,30) {
std::cout << "i is between 10 and 30" << std::endl;
}
std::cout << inspect i -> std::string {
is less_then(10) = "i less than 10";
is in(11,20) = "i is between 11 and 20";
is _ = "i is out of our interest";
} << std::endl;
v : std::vector<int> = ();
if v is empty {
std::cout << "v is empty" << std::endl;
}
} The feature is less generic but still useful. |
cfa2b25
to
a4b33a2
Compare
Rebase to main. Make |
Might require #86 for some use cases. |
a4b33a2
to
370d8aa
Compare
370d8aa
to
c322ec3
Compare
It could be merged. I was not sure if you would be willing to merge all functionalities. |
Can you give an example of what doesn't work? |
The goal was to have each functionality separate. |
NP - if they don't conflict I'll plan to look at them individually for now. Thx! |
@JohelEGP requires { &F::operator(); } It means that the below code will work in the constexpr auto in = [](auto min, auto max) {
return cpp2::lambda_wrapper([](int x, std::pair<int,int> capture) { // <--- explicit type int
return std::get<0>(capture) <= x && x <= std::get<1>(capture);
}, std::pair(min,max));
}; But this will not: constexpr auto in = [](auto min, auto max) {
return cpp2::lambda_wrapper([](auto x, auto capture) { // <--- generic lambda
return std::get<0>(capture) <= x && x <= std::get<1>(capture);
}, std::pair(min,max));
}; |
You could move the constraint to the point where you actually have the argument type |
I will test that direction. Unfortunately,
|
c322ec3
to
1bb321c
Compare
Thanks! Implemented as a separate commit along the lines discussed in #79. |
@hsutter, your change enables using lambda in inspect expressions but not in if statements. My solution worked for both cases ;) #include <iostream>
#include <vector>
constexpr auto less_then = [](int value) {
return [=](auto x) { return x < value;};
};
constexpr auto in = [](auto min, auto max) {
return [=](auto x) {
return min <= x && x <= max;
};
};
constexpr auto empty = [](auto&& x){
return std::empty(x);
};
main: () -> int = {
i := 15;
std::cout << inspect i -> std::string {
is (less_then(10)) = "i less than 10"; // works
is (in(11,20)) = "i is between 11 and 20"; // works
is _ = "i is out of our interest";
} << std::endl;
if i is (less_then(20)) { // not working
std::cout << "less than 20" << std::endl;
}
if i is (in(10,30)) { // not working
std::cout << "i is between 10 and 30" << std::endl;
}
v : std::vector<int> = ();
if empty(v) { // works
std::cout << "v is empty" << std::endl;
}
if v is (empty) { // not working
std::cout << "v is empty" << std::endl;
}
} |
Ah, you noticed that. :) That was next on my to-do list, and I just checked it in... the above code now works with commit 327ceeb . |
In https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2392r0.pdf there is an example that uses lambda with
is
keyword.or
I started to experiment with current implementation to achieve the same functionality and I came up with implementation that you can check here: https://godbolt.org/z/464PP7bW6 (working prototype).
Unfortunately lambda with the capture list cannot be argument of the template (only gcc supports that). So, I have created a wrapper that stores a lambda and the arguments that normally will go to the capture list.
lambda_wrapper
shall usestd::tuple
to store arguments that shall go to capture list butstd::tuple
is not structural type and cannot be used in that context. There are possible workarounds (https://stackoverflow.com/questions/69194075/structural-tuple-like-wrapping-a-variadic-set-of-template-parameters-values-in) but I decided to propose something simple.The current implementation can handle lambda that captures:
std::monostate
that is default second template argument type (lambda_wrapper([](auto x){/**/})
),lambda_wrapper([](auto x, auto capture){/**/}, captured_value)
),std::pair
(lambda_wrapper([](auto x, auto capture){/**/}, std::pair(/* captured two values */) )
),If more captured values will be needed we need to add tuple-like structure that will be structural type.
On the last push I have made possible using
lambda_wrapper
in inspect alternatives (by makingid-expression ( expression-list )
an valid alternative syntax.That makes this code works: