[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
iskeyword.cout << inspect i -> std::string { is in(1,2) = "1 or 2"; is in(2,3) = "3"; is _ = "something else"; };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_wrappershall usestd::tupleto store arguments that shall go to capture list butstd::tupleis 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::monostatethat 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_wrapperin inspect alternatives (by makingid-expression ( expression-list )an valid alternative syntax.That makes this code works:
std::cout << inspect i -> std::string { is less_than(10) = "i less than 10"; is in(11,20) = "i is between 11 and 20"; is _ = "i is out of our interest"; } << std::endl;