Passing a lambda with moved capture to function - c++

I recently struggled with a bug hard to find for me. I tried to pass a lambda to a function taking a std::function object. The lambda was capturing a noncopyable object.
I figured out, obviously some copy must happen in between all the passings. I came to this result because I always ended in an error: use of deleted function error.
Here is the code which produces this error:
void call_func(std::function<void()> func)
{
func();
}
int main()
{
std::fstream fs{"test.txt", std::fstream::out};
auto lam = [fs = std::move(fs)] { const_cast<std::fstream&>(fs).close(); };
call_func(lam);
return 0;
}
I solved this by capseling the std::fstream object in an std::shared_ptr object. This is working fine, but I think there may be a more sexy way to do this.
I have two questions now:
Why is this error raising up?
My idea: I generate many fstream objects and lambdas in a for loop, and for each fstream there is one lambda writing to it. So the access to the fstream objects is only done by the lambdas. I want do this for some callback logic. Is there a more pretty way to this with lambdas like I tried?

The error happens because your lambda has non-copyable captures, making the lambda itself not copyable. std::function requires that the wrapped object be copy-constructible.
If you have control over call_func, make it a template:
template<typename T>
void call_func(T&& func)
{
func();
}
int main()
{
std::fstream fs{"test.txt", std::fstream::out};
auto lam = [fs = std::move(fs)] { const_cast<std::fstream&>(fs).close(); };
call_func(lam);
}
Following is my take on your idea in (2). Since std::function requires the wrapped object to be copy-constructible, we can make our own function wrapper that does not have this restriction:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <utility>
#include <memory>
#include <sstream>
#include <vector>
template<typename T>
void call_func(T&& func) {
func();
}
// All functors have a common base, so we will be able to store them in a single container.
struct baseFunctor {
virtual void operator()()=0;
};
// The actual functor is as simple as it gets.
template<typename T>
class functor : public baseFunctor {
T f;
public:
template<typename U>
functor(U&& f)
: f(std::forward<U>(f))
{}
void operator()() override {
f();
}
};
// In C++17 you don't need this: functor's default constructor can already infer T.
template<typename T>
auto makeNewFunctor(T&& v) {
return std::unique_ptr<baseFunctor>(new functor<T>{std::forward<T>(v)});
}
int main() {
// We need to store pointers instead of values, for the virtual function mechanism to behave correctly.
std::vector<std::unique_ptr<baseFunctor>> functors;
// Generate 10 functors writing to 10 different file streams
std::generate_n(std::back_inserter(functors), 10, [](){
static int i=0;
std::ostringstream oss{"test"};
oss << ++i << ".txt";
std::fstream fs{oss.str(), std::fstream::out};
return makeNewFunctor([fs = std::move(fs)] () mutable { fs.close(); });
});
// Execute the functors
for (auto& functor : functors) {
call_func(*functor);
}
}
Note that the overhead from the virtual call is unavoidable: Since you need functors with different behavior stored in the same container, you essentially need polymorphic behavior one way or the other. So you either implement this polymorphism by hand, or use virtual. I prefer the latter.

Related

Unique id for any kind of callable object in C++17

In one part of my code, I have an abstract function type Function which represents any kind of callable and which can be stored in a heterogeneous container, e.g. std::vector<std::unique_ptr<Function>>:
#include <any>
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <cassert>
class Function
{
public:
Function(std::string name)
: m_name(name)
{}
virtual ~Function(){}
std::string name() {
return m_name;
}
template <typename... Args>
decltype(auto) operator()(Args&&... args)
{
// delegate to invoke, implementation not relevant for question
}
private:
std::string m_name;
// the following is also simplified for the sake of brevity
virtual std::any invoke(std::initializer_list<std::any> const& args) const = 0;
};
template <typename F>
class FunctionImpl : public Function
{
public:
FunctionImpl(F const& f, std::string name)
: Function(name)
, function(f)
{}
private:
std::any invoke(std::initializer_list<std::any> const& args) const override
{
// implementation not relevant for question
return std::any();
}
F function;
};
using FPointer = std::unique_ptr<Function>;
template <typename F>
FPointer make_function(F const& f, std::string name)
{
return std::make_unique<FunctionImpl<F>>(f, name);
}
Now I want to add a function
using FContainer = std::vector<FPointer>;
template <typename F>
bool contains(FContainer const& vec, F const& f)
{
// ?????
}
which returns true, if the function passed as argument in contained in the container, and false otherwise (and probably in a follow-up step a function that returns a reference to the element in the container, if it is contained). How would I write this kind of function? What are my options?
void bar(){}
void foo(){}
struct AClass {
void MemberFunction1(){}
void MemberFunction2(){}
};
struct ACallableClass
{
void operator()(){}
};
int main()
{
FContainer v;
// function pointer
v.push_back(
make_function(
&foo,
"foo"
)
);
// std::function
v.push_back(
make_function(
std::function<void()>(&foo),
"foo"
)
);
// member function
v.push_back(
make_function(
&AClass::MemberFunction1,
"AClass::MemberFunction1"
)
);
// callable
v.push_back(
make_function(
ACallableClass(),
"CallableClass"
)
);
// lambda
v.push_back(
make_function(
[](){},
"empty lambda"
)
);
assert(contains(v, &foo));
assert(contains(v, std::function<void()>(&foo)));
assert(contains(v, &AClass::MemberFunction1));
assert(!contains(v, [](){})); // every lambda is different
assert(!contains(v, &bar));
assert(!contains(v, std::function<void()>(&bar)));
assert(!contains(v, &AClass::MemberFunction2));
return 0;
}
The best solution I could come up with so far was to write a function template
template <typename F> size_t id(F&& id);
that gives a unique id to any kind of callable. Then Function could get a new virtual size_t id() const = 0 method, which would be overwritten by Function<F>. The latter delegates to the free function template. With this, I could compare ids in contains.
I tried implementing the function template using std::hash with function pointers, but I got stuck at hashing member function pointers, callable classes and lambdas. Here is my latest approach: https://godbolt.org/z/zx4jnYbeG.
Sorry for the rather lengthy question. Any help would be greatly appreciated!
EDIT 1:
I can live without std::function support. I would like to support lambdas in principle, but I can live with contains always returning false for lambdas, which makes sense to me. I do want the code to work with function pointers, callable classes and member functions.
EDIT 2:
Here is a working solution based on the suggestions in xryl669s answer: https://godbolt.org/z/vYGesEsKa. std::function<F> and F get the same id, but I suppose this actually make sense, since they are basically equivalent.
Use an unordered_map and not a vector to store your functions.
The key can be derived from the name (probably better anyway), or from the address of the function, but in that case, you'll have an issue with everything that's not a real function (like a method, a std::function<> instance, a lambda, ...)
But since you probably have an issue already with your make_function for methods (you don't capture the instance), you can probably make a specialization for that case using a lambda or a template trampoline and use that address instead.
Another issue to account for is:
std::function<>(&foo) != std::function<>(&foo) (you have 2 instances, they are 2 different objects)
Similarly for lambda functions, two different instance containing the same lambda body won't match anyway.
Compiler is allowed to generate copies of functions if it has all the code for them and it's doing so unless you build with -Os or use external linkage for your functions
So, unless you fallback to a unique identifier that you assign to your Function, you can't assert that a function is identical to another based on the function's body or some instance.
Example (working) godbolt for the specialized template approach: https://godbolt.org/z/8sP5MfG6r
Please notice that you can't store a &foo and std::function<>(&foo) in the container in this approach if using the std::function<>::target() as the key, they'll point to the same function and thus will be overwritten or not inserted since they already exist, but that's probably a good thing for your application it seems.
If you don't care about UB, you can use this version: https://godbolt.org/z/9GoEWMnMb that's reinterpret_cast'ing the function's pointer (and pointer to method too) to use as the hash's key in the map. That's not clean, but since we don't use the result of the cast to call the function, it shouldn't bother much.

How to Store Variadic Template Arguments Passed into Constructor and then Save them for Later Use?

I am curious how one would go about storing a parameter pack passed into a function and storing the values for later use.
For instance:
class Storage {
public:
template<typename... Args>
Storage(Args... args) {
//store args somehow
}
}
Basically I am trying to make a class like tuple, but where you don't have to specify what types the tuple will hold, you just pass in the values through the constructor.
So for instance instead of doing something like this:
std::tuple<int, std::string> t = std::make_tuple(5, "s");
You could do this:
Storage storage(5, "s");
And this way you could any Storage objects in the same vector or list. And then in the storage class there would be some method like std::get that would return a given index of an element we passed in.
Since run will return void, I assume all the functions you need to wrap can be functions that return void too.
In that case you can do it like this (and let lambda capture do the storing for you):
#include <iostream>
#include <functional>
#include <string>
#include <utility>
class FnWrapper
{
public:
template<typename fn_t, typename... args_t>
FnWrapper(fn_t fn, args_t&&... args) :
m_fn{ [=] { fn(args...); } }
{
}
void run()
{
m_fn();
}
private:
std::function<void()> m_fn;
};
void foo(const std::string& b)
{
std::cout << b;
}
int main()
{
std::string hello{ "Hello World!" };
FnWrapper wrapper{ foo, hello };
wrapper.run();
return 0;
}
OK, what you're asking is type erasure. Typical way of implementing it is via a virtual function inherited by a class template.
Live demo here: https://godbolt.org/z/fddfTEe5M
I stripped all the forwards, references and other boilerplate for brevity. It is not meant to be production code by any means.
#include<memory>
#include <iostream>
#include <stdexcept>
struct Fn
{
Fn() = default;
template<typename F, typename...Arguments>
Fn(F f, Arguments...arguments)
{
callable =
std::make_unique<CallableImpl<F, Arguments...>>(f, arguments...);
}
void operator()()
{
callable
? callable->call()
: throw std::runtime_error("empty function");
}
struct Callable
{
virtual void call() =0;
virtual ~Callable() = default;
};
template<typename T, typename...Args_>
struct CallableImpl : Callable
{
CallableImpl(T f, Args_...args)
: theCallable(f)
, theArgs(std::make_tuple(args...))
{}
T theCallable;
std::tuple<Args_...> theArgs;
void call() override
{
std::apply(theCallable, theArgs);
}
};
std::unique_ptr<Callable> callable{};
};
void f(int a)
{
std::cout << a << '\n';
}
int main(int, char*[])
{
Fn fx{f, 3};
fx();
char x = 'q';
Fn flambda( [x](){std::cerr << x << '\n';} );
flambda();
}
The "meat" of it lies here:
struct Callable
{
virtual void call() =0;
virtual ~Callable() = default;
};
template<typename T, typename...Args_>
struct CallableImpl : Callable
{
CallableImpl(T f, Args_...args)
: theCallable(f)
, theArgs(std::make_tuple(args...))
{}
T theCallable;
std::tuple<Args_...> theArgs;
void call() override
{
std::apply(theCallable, theArgs);
}
};
Callable is just the interface to access the object. Enough to store a pointer to it and access desired methods.
The actual storage happens in its derived classes:template<typename T, typename...Args_> struct CallableImpl : Callable. Note the tuple there.
T is for storing the actual object, whatever it is. Note that it has to implement some for of compile-time interface, in C++ terms referred to as a concept. In that case, it has to be callable with a given set of arguments.
Thus it has to be known upfront.
The outer structure holds the unique_ptr to Callable but is able to instantiate the interface thanks to the templated constructor:
template<typename F, typename...Arguments>
Fn(F f, Arguments...arguments)
{
callable =
std::make_unique<CallableImpl<F, Arguments...>>(f, arguments...);
}
What is the main advantage of it?
When done properly, it has value semantics. Effectively, it can be used to represent a sort of polymorphism without derivation, note T doesn't have to have a common base class, it just has to be callable in one way or another; this can be used for addition, subtraction, printing, whatever.
As for the main drawbacks: a virtual function call (CallableImpl stored as Callable) which may hinder performance. Also, getting back the original type is difficult, if not nearly impossible.

How to remove a std::function<void()> in vector?

I'm trying to create C# event in c++ for my game engine. I'm implementing the event system now but I don't know how to remove a std::function in a vector. Am I using the correct list?
I'm quite new in C++ but I'm a C# programmer for 10 years now. Is this possible in C++?
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
struct Delegate {
std::vector<std::function<void()>> funcs;
template<class T> void operator+=(T mFunc)
{
funcs.push_back(mFunc);
}
template<class T> void operator-=(T mFunc)
{
// How?
//funcs.erase(std::remove(funcs.begin(), funcs.end(), mFunc), funcs.end());
}
void operator()() {
for (auto& f : funcs) f();
}
};
void fun1()
{
std::cout << "hello, ";
}
void fun2()
{
std::cout << "Delete";
}
void fun3()
{
std::cout << "world!" << std::endl;
}
int main() {
Delegate delegate;
delegate += fun1;
delegate += fun2;
delegate -= fun2;
delegate += fun3;
delegate();
}
If you are willing to limit Delegate to only using function pointers the you can do it with what you have. That would look like
struct Delegate {
std::vector<void(*)()> funcs;
template<class T> void operator+=(T mFunc)
{
funcs.push_back(mFunc);
}
template<class T> void operator-=(T mFunc)
{
funcs.erase(std::remove(funcs.begin(), funcs.end(), mFunc), funcs.end());
}
void operator()() {
for (auto& f : funcs) f();
}
};
If you don't want to do so, then you need to change you approach. You could have operator += return an index to the inserted function, and then you can change operator -= to take that index and remove that element. see eerorika's answer for a suggestion on how to return iterators to the functions.
Is this possible in C++?
Not like this. Function wrappers cannot be compared for equality. This is a limitation in their design.
One option is to use function pointers. They can be compared for equality. But then you cannot use stateful function objects. NathanOliver shows an example of this.
Another alternative design would be to use a std::list as the container, and when ever you register a function, return iterator to it. Then, instead of erasing by passing the function, you can pass the iterator to be erased.
std::function objects are not directly comparable, but if you are only using regular functions (not e.g. member functions or capturing lambdas), you can use target() method to extract underlying pointer.
void operator-=(void(*mFunc)())
{
auto pred = [&mFunc](const std::function<void()>& func) { return mFunc == *func.target<decltype(mFunc)>(); };
funcs.erase(std::remove_if(funcs.begin(), funcs.end(), pred), funcs.end());
}
I changed the type T to be function pointer explicitly, because std::function would need a different approach (calling target() on that too). You can overload your operator -= to handle std::function separately.
It's ugly, but it works.
Note: Above snippet doesn't really take into account type safety. target() will return nullptr if type declared by template does not match the actual type stored by std::function, and dereferencing nullptr will be disastrous. Since your code only seems to deal with free functions of signature void(), it shouldn't be much issue, but if you plan to use lambdas or something it may break.

auto x = make_x(...) and this

I have a class template S<T> and because the template parameter is sometimes hard write explicitly I also have a little helper function makeS(...) to deduce the template parameter.
Now the problem is that the constructor of S has a "side effect": it adds itself to a map which then will later be used to iterate over all instances of S. But this effectively makes S<T> s{...}; very different from auto s = makeS(...); (if RVO is not used).
Here is some code which hopefully shows what I'm trying to do. (Note: in the actual program, S has more than a single template parameter and all will be deduced in makeS)
#include <cassert>
#include <iostream>
#include <map>
#include <string>
#include <utility>
using namespace std;
struct Base
{
virtual ~Base() {}
virtual void f() const = 0;
};
static map<string, Base*> Map;
template <typename T>
struct S : Base
{
T Func;
Base* This;
S(string const& name, T func) : Func(std::move(func)), This(this)
{
//
// Automatically add this struct to Map...
//
Map.insert({name, this});
}
virtual void f() const override { Func(); }
};
template <typename T>
S<T> makeS(std::string const& name, T func)
{
return S<T>(name, std::move(func));
}
void func1()
{
std::cout << "func1\n";
}
int main()
{
struct Func2
{
void operator ()() const {
std::cout << "func2\n";
}
};
//
// This is not possible:
//
// S< ??? > s("s", [](){});
//
// This would be ok:
//
// auto F = [](){};
// S<decltype(F)> s("s", F);
//
auto s1 = makeS("s1", func1);
auto s2 = makeS("s2", Func2());
auto s3 = makeS("s3", [](){ std::cout << "func3\n"; });
//
// Manually adding s1,... to the Map is ok, but that's what
// I want to avoid...
//
// Map.insert({"s1", &s1});
// ...
//
assert(&s1 == s1.This);
assert(&s2 == s2.This);
assert(&s3 == s3.This);
for (auto&& I : Map)
{
I.second->f();
}
}
As I understand it, the map will only contain valid pointers if RVO is used in auto s1 = makeS(...) etc. and this is not guaranteed.
Is there a way to deduce the template parameters while at the same time avoiding the need to manually register s1,...?
Your basic problem is you failed to implement the rule of 3. If your destructor needs non-trivial behavior (and if you register yourself in the constructor, this is the case), you must either implement or block assignment and copy construct (and/or move-assign and move-construct).
In this case, we can implement a move-construct and block move-assign, and copy construct and copy assign are implicitly blocked.
First, add name to S. Then implement a move constructor.
template <typename T>
struct S : Base
{
std::string Name;
T Func;
Base* This; // ?? why ?? this looks both dangerous and useless at the same time!
S( S&& s ): Name(std::move(s.Name)), Func(std::move(s.Func)), This(this) {
s.clear(); // technically `move` need not clear.
map[Name] = this; // overwrite
}
S& operator=(S&& s) = delete; // or implement it
now your object is moveable, and when moved it updates the Map. ~S should, I assume, unregister from Map -- detect if your name is empty (and assert at construction you gain a non-empty name), and if it is don't unregister (as you where already moved from).
Now move-construct and elided-construct have the same semantics. RVO failure results in some inefficiency, but no logical failure. Plus, your type is now moveable, which tends to be really useful.
If you need to maintain object identity, use can use std::unique_ptr:
template <typename T>
std::unique_ptr<S<T>> makeS(std::string const& name, T func)
{
return { new S<T>(name, std::move(func)) };
}
Now moving the pointer from place to place won't move the object; the pointer kept in the map will stay valid.
My suggestions to improve your code:
1) Get rid of the side effect in the constructor. Create objects in a factory method only (makeS in your code; you can make it a static member function of S) and register the S objects in that method. To disable object creation in different ways make constructor(s) private.
2) Disable S objects copying/moving and handle the objects for example as shared_ptr/unique_ptr<S> only. When you disable copying/moving you avoid the problem when your map contains a pointer to invalid objects and now you don't need to rely on RVO.
3) Use std::function<void()> instead of T Func;. In that case your class don't need to be a template class (or it will have less template arguments). That will simplify your code.

Best practice for local variable scope in a C++ callback

I have a functioning C++ callback function, triggered by a user 'mouse down' event. (The IDE is VS2010.)
With each call, I'd like to increment a simple count variable that is local to the callback's scope. Simply put, what is the 'best practices' way to do this?
Thanks in advance for any opinions or directives.
Replace your callback function with a functor - they can store state. An example functor:
#include <iostream>
#include <memory>
class Functor
{
private:
std::shared_ptr<int> m_count;
public:
Functor()
: m_count(new int(0))
{}
void operator()()
{
++(*m_count);
// do other stuff...
}
int count() const
{
return *m_count;
}
};
template <typename F>
void f(F callback)
{
// do stuff
callback();
// do other stuff
}
int main()
{
Functor callback;
f(callback);
f(callback);
std::cout << callback.count(); // prints 2
return 0;
}
Note the use of a shared_ptr inside the functor - this is because f has a local copy of the functor (note the pass-by-value) and you want that copy to share its int with the functor to which you have access. Note also that f has to take its argument by value, since you want to support all callables, and not just functors.