Return from a C++0x lambda caller directly - c++

I've just rewritten the following C89 code, that returns from the current function:
// make sure the inode isn't open
{
size_t i;
for (i = 0; i < ARRAY_LEN(g_cpfs->htab); ++i)
{
struct Handle const *const handle = &g_cpfs->htab[i];
if (handle_valid(handle))
{
if (handle->ino == (*inode)->ino)
{
log_info("Inode "INO_FMT" is still open, delaying removal.",
(*inode)->ino);
return true;
}
}
}
}
With this C++0x STL/lambda hybrid:
std::for_each(g_cpfs->htab.begin(), g_cpfs->htab.end(), [inode](Handle const &handle) {
if (handle.valid()) {
if (handle.ino == inode->ino) {
log_info("Inode "INO_FMT" is still open, delaying removal.", inode->ino);
return true;
}
}});
Which generates:
1>e:\src\cpfs4\libcpfs\inode.cc(128): error C3499: a lambda that has been specified to have a void return type cannot return a value
I hadn't considered that the return in the lambda, doesn't actually return from the caller (having never seen a scoped function in C/C++ before now). How do I return true from the caller where the original function would have done so?

You don't; std::for_each isn't structured to handle an early return. You could throw an exception...
Or don't use a lambda:
for (auto const &handle : g_cpfs->htab) {
// code that was in lambda body
}

Use std::find_if() instead of std::for_each():
if (std::find_if(g_cpfs->htab.begin(), g_cpfs->htab.end(),
[inode](Handle const &handle) {
if (handle.valid() && handle.ino == inode->ino) {
log_info("Inode "INO_FMT" is still open, delaying removal.",
inode->ino);
return true;
}
return false;
}) != g_cpfs->htab.end()) {
return true;
}

Related

Got an Error when using C++20 Polymorphism Lambda Function

I'm trying to write a higher-order function via Lambda in C++, and got this code.
void ProcessList::SortCol(std::string col, bool flag) {
auto CmpGenerator = [&]<typename T>
(std::function<T(const Process &itm)> func) {
return (flag? [&](const Process &a, const Process &b) {
return func(a) < func(b);}
: [&](const Process &a, const Process &b) {
return func(a) > func(b);}
);
};
std::function<bool(const Process &a, const Process &b)> cmp;
if (col == "PID") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetPid();
});
}
else if (col == "CPU") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetRatioCPU();
});
}
else if (col == "COMMAND") {
cmp = CmpGenerator([](const Process &itm) {
return itm.GetCmd();
});
}
std::sort(lst.begin(), lst.end(), cmp);
}
However when compiling, g++ reported that no match for call to
no match for call to ‘(ProcessList::SortCol(std::string, bool)::<lambda(std::function<T(const Process&)>)>) (ProcessList::SortCol(std::string, bool)::<lambda(const Process&)>)’
What's wrong here with the code?
The primary problem in this example is that a lambda is not a std::function. See this question.
CmpGenerator deduces its argument as std::function<T(Process const&)>, but a lambda will never match that, so deduction fails.
Furthermore, the body of CmpGenerator tries to return one of two different lambdas - which have different types. Those lambdas are not convertible to each other, so the conditional expression will fail. But we also can't deduce the return type of CmpGenerator since the two different lambdas have different types.
We can start by doing this completely by hand. std::ranges::sort takes a projection, which is very helpful in this regard:
if (col == "PID") {
if (increasing) { // <== 'flag' is not a great name
std::ranges::sort(lst, std::less(), &Process::GetPid);
} else {
std::ranges::sort(lst, std::greater(), &Process::GetPid);
}
} else if (col == "CPU") {
// ...
}
This gives the structure that we need to abstract: we're not generating a comparison object, we're generating a call to sort.
That is:
auto sort_by = [&](auto projection){ // <== NB: auto, not std::function
if (increasing) {
std::ranges::sort(lst, std::less(), projection);
} else {
std::ranges::sort(lst, std::greater(), projection);
}
};
if (col == "PID") {
sort_by(&Process::GetPid);
} else if (col == "CPU") {
sort_by(&Process::GetRatioCPU);
} else if (col == "COMMAND") {
sort_by(&Process::GetCmd);
}

Can this get to the end of the function and not return anything?

I am making a c++ text based game and while making a feature for eating food I made this function names eating. I am getting a warning saying its possible to reach the end with no return value. How is it possible to get to the end and not return something?
int inventory::eat(std::string eating)
{
if (!consumables.empty())
{
for (int i = 0; i < consumables.size(); i++)
{
if (consumables[i].name == eating)
{
return consumables[i].effect;
}
else
{
return 404;
}
}
}
else
{
return 505;
}
}
Presumably the compiler is unable to tell that if consumables.empty() == false, then consumables.size() > 0.
I'd probably rewrite it as this, but I'm worried about the if/else inside your for loop.
int inventory::eat(std::string eating) {
for (int i = 0; i < consumables.size(); i++) {
if (consumables[i].name == eating) {
return consumables[i].effect;
} else {
return 404;
}
}
return 505;
}
Assuming no other thread modifies consumables while eat() is running, then no, return will not be skipped. But the compiler doesn't know that. It doesn't knower that !empty() and size() > 0 mean the same thing for a container. They are just two separate method calls.
That said, I would suggest writing the code more like this, which is easier to read, and avoids the warning:
int inventory::eat(const std::string &eating)
{
if (consumables.empty())
return 505;
for (int i = 0; i < consumables.size(); ++i)
{
if (consumables[i].name == eating)
return consumables[i].effect;
}
return 404;
}
Or, if you are using C++11 and consumables supports iterators:
#include <algorithm>
int inventory::eat(const std::string &eating)
{
if (consumables.empty())
return 505;
auto found = std::find_if(
consumables.begin(), consumables.end(),
// replace 'consumable' below with your actual type name as needed...
[&](const consumable &c){ return c.name == eating; }
);
if (found != consumables.end())
return found->effect;
return 404;
}

How to check if bool method returns value in an if statement C++

I'm having a go at creating classes and have created this method inside
Input.cpp:
bool Input::CheckKeyPress(char key)
{
SDL_Event ev;
while (SDL_PollEvent(&ev))
{
keyState = SDL_GetKeyboardState(NULL);
if (ev.type == SDL_KEYDOWN)
{
switch (key)
{
case 'w' :
if (keyState[SDL_SCANCODE_W])
{
return 1;
}
else
{
return 0;
}
case 'a' :
if (keyState[SDL_SCANCODE_A])
{
return 1;
}
else
{
return 0;
}
case 's' :
if (keyState[SDL_SCANCODE_S])
{
return 1;
}
else
{
return 0;
}
case 'd' :
if (keyState[SDL_SCANCODE_D])
{
return 1;
}
else
{
return 0;
}
}
}
}
}
I try to use it in an if-statement in my main class like so:
if (bool Input::CheckKeyPress(w))
{
//do stuff
}
However as expected I get an error saying: "A function type is not allowed here" So what do I do?
Just write:
if (CheckKeyPress(w))
{
//do stuff
}
You have already told the compiler that the CheckKeyPress() method returns a bool. Here, you are just calling the function, so you don't need to mention the return type again. When the control will call the function CheckKeyPress(), it will return a bool value that would be checked for its truth within the if statement.
Note: There are two possibilities:
Instance is a different class:
If Instance is altogether a different class and CheckKeyPress() is
one of the methods that it contains, then you first need to create an object of the Instance class like below:
Instance it = new Instance(); //or just Instance it;
and then access the function via:
it.CheckKeyPress();
If the method is static:
In this case you need to call the method as:
Input::CheckKeyPress(w)
without just the return type (bool).
Hope this is helpful. Thank you for your inputs, #user4581301.

Should I use returning functions when the return value isn't needed?

I have a function that looks like this:
int Game::GetInput() {
while (true) {
// do stuff
if (something) {
// do this
return 0;
}
else {
// do other stuff
}
}
}
I'm wondering if it is common or proper to have a returning function, rather than a void function, for the sole purpose of leaving the function (the value being returned wouldn't do anything in the program except for ending the function). Is this good practice, or is there a better way to end a function?
There is no problem with void functions. If it does not return anything useful, it should be void.
Just make your function void, and simply return?
// vv void return type
void Game::GetInput() {
while (true) {
// do stuff
if (something) {
// do this
return; // <<<< No return value
}
else {
// do other stuff
}
}
}
You can easily just use return; with no parameter to exit a void function. Your above code would become:
void Game::GetInput() {
while (true) {
// do stuff
if (something) {
// do this
return;
}
else {
// do other stuff
}
}
}
If there is no useful value for the function to return, it is better not to return a value - because the calling code should check the returned value.
Your code can be doubly simplified:
void Game::GetInput() {
while (true) {
// do stuff
if (something) {
// do this
return;
}
// do other stuff
}
}
The else is unnecessary; the only way to execute the 'do other stuff' is if something is false.

How to implement final conditions properly?

This is what I'm trying to do (this is a simplification of a real project):
int param;
int result;
void isolated(int p) {
param = p;
try {
// make calculations with "param" and place the
// result into "result"
process();
} catch (...) {
throw "problems..";
}
}
I can't change the way process() works, since this function is not created in the project and is a third-party function. It works with global variables param and result and we can't change this.
The problem appears when isolated() is called back from process() with another parameter. I want to catch this situation, but don't know how to do it, since finally is absent in C++. I feel that I should use RAII technique, but can't figure out how to do it in this case properly.
This is how I can make it with code duplication:
int param;
int result;
void isolated(int p) {
static bool running;
if (running) {
throw "you can't call isolated() from itself!";
}
running = true;
param = p;
try {
// make calculations with "param" and place the
// result into "result"
process();
running = false;
} catch (...) {
running = false; // duplication!
throw "problems..";
}
}
"finally" like situations are handled in C++ using guard objects, that do their finally thing in the destructor. This is IMHO much more powerful approach, because you have to analyze the situation to finalize in order to create a reuseable object. In this case, we need to make process rentrant, because parameters and returns are passed in globals. The solution is to save their values on entry and restore them on exit:
template<class T>
class restorer
{
T &var; // this is the variable we want to save/restore
T old_value; // the old value
restorer(const restorer&);
void operator=(const restorer&);
public:
restorer(T &v) : var(v), old_value(v) {}
~restorer() { var=old_value; }
};
int param;
int result;
int isolated(int p) {
restorer<int> rest_param(param);
restorer<int> rest_result(result);
param = p;
try {
// make calculations with "param" and place the
// result into "result"
process();
return result;
} catch (...) {
return 0;
}
}
Maybe I didn't get it right, but why don't you use a flag? You want to know when the isolated() is called from the process(), right?
int isolated(int p) {
static int execDeep = 0;
execDeep++;
// your code here
execDeep--;
}
Now you can check 'execDeep' value, > 1 means it is called from the process() while still being executed.
I still don't quite sure how finally is related here, but you could try Boost.ScopeExit if you want to avoid creating a scope guard structure yourself.
Example:
#include <boost/scope_exit.hpp>
#include <cstdio>
int isolated(int p) {
static bool running = false;
if (running) {
printf("Throwing %d\n", p);
throw p;
}
printf("Starting %d\n", p);
running = true;
BOOST_SCOPE_EXIT( (p)(&running) ) { // <--
printf("Stopping %d\n", p); // <--
running = false; // <--
} BOOST_SCOPE_EXIT_END // <--
// ...
if (p)
isolated(p*10);
// ...
printf("Returing %d\n", p);
return 4;
}
int main() {
printf(">> first\n");
isolated(0);
printf(">> second\n");
try {
isolated(1);
printf(">> third (should not be printed.)\n");
} catch(int p) {
printf("Caught %d\n", p);
}
isolated(0);
printf(">> fourth\n");
return 0;
}
Result:
>> first
Starting 0
Returing 0
Stopping 0
>> second
Starting 1
Throwing 10
Stopping 1
Caught 10
Starting 0
Returing 0
Stopping 0
>> fourth
Could this work?
int save = -10000000000;
int param;
int result;
int isolated(int p) {
if (save != -10000000000)
{
// run the other condition
}
else
{
save = p;
param = p;
try {
// make calculations with "param" and place the
// result into "result"
process();
return result;
} catch (...) {
return 0;
}
}
}
If I understand correctly, you want to automatically set the running flag to false at the end of function. If that is the requirement then you can use the ScopeGuard approarch mentioned in the link.