I need to use a tuple in my code to be able to conveniently store three data with different type in a vector. That is to say, I have something like this :
std::vector<std::tuple<sf::Time, sf::Time, std::function<void()> > > m_timedFunctions;
Where the first sf::Time represent how often should we call the std::function, and the second sf::Time represent the timestamp of the last call to the function. The goal is to be able to call a function at regular interval automatically.
I have no problem creating and inserting a tuple into the vector, but for some reason when I try to modify the second sf::Time using std::get<1>(u), it just does not happen. I can read the data perfectly, but in no way it lets me modify it.
Here's how I create the tuple :
void addTimedFunction(sf::Time freq, std::function<void()> f)
{
auto a = std::make_tuple(freq, sf::seconds(0), f);
m_timedFunctions.push_back(a);
}
but later if I do something like this : std::get<1>(a) = sf::seconds(10); (where a is a tuple from m_timedFunctions that I get with a ranged-base for), the second member stays at 0.
The whole part of my code where I'm modifying it :
void MainWindow::processTimedFunctions()
{
for(auto a : m_timedFunction)
{
sf::Time elapsed = m_clock.getElapsedTime();
sf::Time lastExec = std::get<1>(a);
sf::Time diff = elapsed - lastExec;
if( diff.asMilliseconds() >= std::get<0>(a).asMilliseconds())
{
std::get<1>(a) = sf::seconds(10); // m_clock.getElapsedTime(); // Update the last execution time
std::get<2>(a)(); // Call the linked function
}
}
}
How can I effectively modify it ?
This creates a copy of the elements you're iterating over:
for(auto a : m_timedFunction)
Any changes you make to a will not affect the container.
To get a reference instead of a copy, use:
for(auto &a : m_timedFunction)
Related
I have a scenario where I am working with temporal data in Apache Arrow and am using compute functions to extract date/time components like so:
auto year = arrow::compute::CallFunction("year", {array});
auto month = arrow::compute::CallFunction("month", {array});
auto day = arrow::compute::CallFunction("day", {array});
...
While this works, I have to manage three separate Datums. I would ideally like to have one function that returns a StructArray containing year/month/day elements, which can also scale out to more detailed time components. Is there a simply way of registering such a function with the current API?
Is there a simply way of registering such a function with the current API?
I don't think so, your use case looks too specific. On the other hand if you do that often you can implement something that would do it for you:
std::shared_ptr<arrow::Array> CallFunctions(std::vector<std::string> const& functions,
std::vector<arrow::Datum> const& args) {
std::vector<std::shared_ptr<arrow::Array>> results;
for (std::string const& function : functions) {
results.push_back(arrow::compute::CallFunction(function, args).ValueOrDie().make_array());
}
return arrow::StructArray::Make(results, functions).ValueOrDie();
}
void test() {
auto array = ....
auto structArray = CallFunctions({"year", "month", "day"}, {array});
}
Assume that I have a functionality which I want to call whenever a timer finishes. I have put that piece of functionality in a lambda function. Furthermore, in that function, I may wish to set another timer to call that same lambda on another, later occasion.
void doSetupThingsInSomeDecoupledCodeOrWhatever() {
std::function<void(float)> semiRecursiveFunc;
semiRecursiveFunc = [&semiRecursiveFunc](float deltaT){
if (whatever()) {
// Do something...
}
else {
// Do something else, then:
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f)
// Gives the timer a duration to wait, and a function to run at the end of it.
getTimerSystem().setNewTimer(durationMS, semiRecursiveFunc);
}
};
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f)
// Gives the timer a duration to wait, and a function to run at the end of it.
getTimerSystem().setNewTimer(durationMS, fooLambda);
}
Now, clearly this won't work, because semiRecursiveFunc is tied to the scope of doSetupThingsInSomeDecoupledCodeOrWhatever, and when the timer system tries to run it the function will no longer exist and everything will disintegrate into a spectacular ball of flame.
What's the best way to manage this? I can't store semiRecursiveFunc in a pointer because one can't declare lambdas like that, as far as I can tell. Is there some common tool for this sort of persistent-lambda use-case? What's the least ugly approach, with minimum surrounding infrastructure? Is there a best-practice to follow, some relevant tool I've missed? Any suggestions or recommendations would be much appreciated.
What you're looking for is a y-combinator, sometimes called a fixed-point combinator.
Either way, instead of using std::function at all (which adds needless overhead), you would write your callback like this:
auto semiRecursiveCallback = combinator([](auto self, float deltaT){
if (whatever()) {
// Do something...
}
else {
// Do something else, then:
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f)
// Gives the timer a duration to wait, and a function to run at the end of it.
// NB: we pass 'self' as the argument
getTimerSystem().setNewTimer(durationMS, self);
}
});
Where combinator is either the y_combinator implementation of my linked answer or boost::hof::fix from the excellent Boost.HOF library.
The combinator ensures that the object itself has access to itself, so you can do recursive things. In the above code, you're actually getting passed a copy of yourself, but that's fine: value semantics are cool like that.
Here is a tiny Y-combinator:
template<class R>
auto Y = [] (auto f) {
auto action = [=] (auto action) {
return [=] (auto&&... args)->R {
return f( action(action),decltype(args)(args)... );
};
};
return action(action);
};
Just do this:
auto semiRecursiveFunc = Y<void>([](auto&& semiRecursiveFunc, float deltaT){
if (whatever()) {
// Do something...
}
else {
// Do something else, then:
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f)
// Gives the timer a duration to wait, and a function to run at the end of it.
getTimerSystem().setNewTimer(durationMS, semiRecursiveFunc);
}
);
and it works.
Y<R> takes a callable that is passed what to recurse on as its first argument. When you recurse, just pass the rest of the arguments.
You can write a fancier Y combinator. This one copies the lambdas state a lot and isn't picky about moving it, to keep its implementation simple. It also requires you provide its return type (that is harder to avoid, due to C++ type deduction rules).
Here's a way that is in the style of Objective-C reference counting. The advantage is that you can use a lambda signature that is the same as the original function you want (no extra arguments). The disadvantages are that it looks ugly and verbose, and you have to always use the lambda through a shared_ptr; you can't take it out and pass it separately.
void doSetupThingsInSomeDecoupledCodeOrWhatever() {
std::shared_ptr<std::weak_ptr<std::function<void(float)>>> weakFuncHolder =
std::make_shared<std::weak_ptr<std::function<void(float)>>>();
std::shared_ptr<std::function<void(float)>> semiRecursiveFunc =
std::make_shared<std::function<void(float)>>([=](float deltaT) {
std::shared_ptr<std::function<void(float)>> strongFunc(*weakFuncHolder);
if (whatever()) {
// Do something...
}
else {
// Do something else, then:
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f);
// Gives the timer a duration to wait, and a function to run at the end of it.
getTimerSystem().setNewTimer(durationMS,
[=](float deltaT){ (*strongFunc)(deltaT); });
}
});
*weakFuncHolder = semiRecursiveFunc;
float durationMS = getRNGSystem().getUniformFloat(1000.0f, 5000.0f);
// Gives the timer a duration to wait, and a function to run at the end of it.
getTimerSystem().setNewTimer(durationMS,
[=](float deltaT){ (*semiRecursiveFunc)(deltaT); });
}
I'm writing an Object Oriented version of FCFS scheduling algorithm, and I've hit a problem. I need to know if there's any way to access an array of objects inside the member function definition, without passing it as a parameter explicitly.
I've tried using "this-pointer", but since the calculation of finish time of current process requires the finish time of the previous, "this" won't work. Or at least I think it won't. I have no idea how to access "previous" object using "this"
void Process :: scheduleProcess(int pid) {
if(pid == 0) finishTime = burstTime;
else finishTime = burstTime +
this->[pid-1].finishTime;
turnAroundTime = finishTime - arrivalTime;
waitingTime = turnAroundTime - burstTime;
}
I can obviously send the array of objects as a parameter and use it directly. I just want to know if there's a better way to do this:
This is the part that's calling the aforementioned function:
for(int clockTime = 0; clockTime <= maxArrivalTime(process);
clockTime++) {
// If clockTime occurs in arrivalTime, return pid of that
process
int pid = arrivalTimeOf(clockTime, process);
if(pid >= 0) {
process[pid].scheduleProcess(pid);
} else continue;
}
Since I'm calling scheduleProcess() using process[pid], which is a vector of objects, I should be able to manipulate the variables pertaining to process[pid] object. How do I access process[pid-1] in the function itself? (Without passing process vector as an argument)
Since scheduleProcess is a member of Process, it only knows what the Process object knows. The previous process is unknown at this level. There are ways that use Undefined Behavior and make more assumptions about your code to get around this, but these should be avoided.
One portable solution to avoid all that is to simply pass in the previous process's finish time as a parameter, since you know this value at the point of the call to scheduleProcess. Where there is not a previous process (the first entry in the array), this finish time would be 0.
I have a dream. That I can store lambda expressions passed to a function in a vector as objects wrapped in a class.
These are then run at a given point later and if their have a return value, it is obtained.
I've been trying find a way to do this, e.g. my other post hit a standstill Vector with objects that have function pointers of varying type
The reason I want it this way is so that it is as dynamic and easy to use in any scenario as possible.
In the current case, it's to be used in evolutionary algorithms that perform tasks across separate processes and memory spaces.
Is my dream unfeasible, or bad design? Do you know a better way? I've been at this for days without having anything that compiles.
I'd be grateful to be pointed in the right direction.
Basically something along these lines:
std::vector<CallbackJob> myCallbackList;
std::vector<CallbackJobResult> myCallbackResultList;
Callback myCB = make_callback( [&]{ return Task->Test("I return boolean"); } );
Callback myCB2 = make_callback( [&]{ return Foo("I return doubles"); } );
CallbackJob job1("name1", myCB, 1);
CallbackJob job2("name2", myCB2, 5);
myCallbackList.push_back(job1);
myCallbackList.push_back(job2);
for(auto &i : myCallbackList) {
// maybe need to check if it has a return value, embed it into the callback object itself?
myCallbackResultList.push_back( i.callback() );
}
You can use type erasure, for instance std::any and std::function, to store lambdas and their resulting values in vectors:
std::vector<std::function<std::any()>> functions;
functions.emplace_back([]{ return std::any(1.0); });
functions.emplace_back([]{ return std::any(true); });
std::vector<std::any> results;
for (auto & f : functions)
results.emplace_back(f());
The question is how to process the elements of results, since you need to know their types to cast them with std::any_cast. In this example, you can use, e.g.:
for (const auto & r : results)
if (r.type() == typeid(double))
std::cout << std::any_cast<double>(r);
else if (r.type() == typeid(bool))
std::cout << std::any_cast<bool>(r);
Also note that this will work only if all lambdas have either no parameters or, eventually, parameters of the same type.
I have a functor that creates a linearly spaced set of values . . .
//Linear spaced generator
struct gen_lin {
float mi, inc;
public:
gen_lin(float _mi=1.f, float _inc=1.f) : mi(_mi), inc(_inc){};
float operator()() {
return mi+=inc;
}
};
And I can fill a vector with values like so ...
const size_t elements = 400;
std::vector<float> x(elements);
std::generate_n(x.begin(), elements, gen_lin(10.f,5.f) );
Now, I can easily convert this to a log scale using a lambda like so ...
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
But when I try to squeeze it all on to one line, the vector is entirely filled with the value of logf(10.)
std::generate_n(x.begin(), elements, [](){return logf( gen_lin(10.f,5.f)() );} );
Why, and is it possible to tweak my last line of code to make it work?
With this, you are creating a single gen_lin object, and using it multiple times:
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
With this, you are creating several gen_lin objects:
std::generate_n(x.begin(), elements, [](){return logf( gen_lin(10.f,5.f)() );} );
Each time you create a new gen_lin object, the current value gets reset.
In the first case:
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
You have a persistent gen_lin object, lin, that gets updated with every call to the lambda. But with your one-liner, you are just creating fresh gen_lin object with every call to the lambda, getting the first value that it returns, and then throwing the object away. Since it's a fresh object, initialized with the same constant values, it's going to give you the same value every time.
Each lamdas call creates a new instance of your functor in the second case.
Stuff like bind might fix your problem. Make the lambda take your functor as an argument and use bind to attach a common instance to that argument?
Or use a compose functor of whatever flavour.