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

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.

Related

How to create a Map in C++ that associates functions to parameters?

Consider that you want to call 100 functions sequentially.
I want to create a map that holds function pointers and function parameters, so that i can iterate the map and call each function with the associated parameters.
The arguments are of different type, arity and return type. Is it possible to implement such map in C++?
Pseudocode
for function in map
// call the function with the arguments from the map
function(map[function])
As stated in the comments, this question is too broad. Therefore, there are too many possible solutions. Also, I really wonder why you need this kind of map of functions. I'm sure if you explained your problem, many would advise you a different kind of solution.
That said, I find the subject interesting, and tried to implement a possible solution to your problem.
As the subject is very broad and the question not specific enough, I had to make some decisions (also based on the comments):
I used a set instead of a map as I had no idea what the (key,value) of the map should be.
I just print out the results (assuming the result is printable), as I have no idea what to do with the result.
Instead of function pointers, I used function objects.
As I was not able to fully understand the pseudo code, the functions are called by an invoke function.
Modifying the below example code should allow you to get what you exactly want. The below code is just an example of what kind of ingredients you might need.
GenericFunction and the set
You can only save one type in a set (or map), so you need some GenericFunction class:
class GenericFunction
{
public:
virtual ~GenericFunction() = default;
virtual void invoke() const = 0; // the method to invoke the function
};
Now, you can define a set which will contain pointers to GenericFunction objects:
std::set<GenericFunction*> myFcts;
Specific function class
Next, let's implement the specific function class which derives from the GenericFunction class. The goal of this class is to store the function and arguments of your choice, and to provide an implementation of the invoke function.
#include <iostream>
#include <tuple>
template <typename Fct, typename ... Args>
class MyFct : public GenericFunction
{
public:
MyFct(Fct fct, Args&& ... args) :
_fct { std::move(fct) },
_args { std::forward<Args>(args)... }
{}
void invoke() const override { std::cout << std::apply(_fct,_args) << std::endl; }
private:
Fct _fct;
std::tuple<Args ...> _args;
};
Testing: sum function
For testing, let's write a simple sum function:
template <typename T>
auto sum(T a)
{
return a;
}
template <typename F, typename ... R>
auto sum(F first, R ... rest)
{
return first + sum(rest...);
}
main function
We can now use the above code like this:
#include <set>
int main()
{
// function wrapper
auto sum_wrapper = [](auto&&... args)
{
return sum(std::forward<decltype(args)>(args)...);
};
// create a specific function
MyFct myf1(sum_wrapper, 1, 2.33/*, add the args of your choice*/);
// create another specific function
MyFct myf2(sum_wrapper, 10, 2.33/*, add the args of your choice*/);
// create the set
std::set<GenericFunction*> myFcts { &myf1, &myf2 };
// call the functions
for (const auto& f : myFcts)
f->invoke();
return 0;
}

Passing a lambda with moved capture to function

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.

Trying to push_back into a vector pointing to an abstract class

Compiling my code that contains this class:
class Dessin
{
private:
vector<Figures*>T;
public:
void ajouteFigure(const Figures& f) const
{
for(auto element: T)
{
T.push_back(f);
}
}
};
yields an error:
[Error] no matching function for call to
'std::vector::push_back(const Figures&) const'
This is what I'm supposed to do in the main()
Dessin s;
s.ajouteFigure(Cercle(1.1));
Why wouldn't this work?
Assuming Cercle is a class name, you're trying to push a value where a pointer is expected.
To "fix" the error you should change your ajouteFigure prototype to accept Figures pointers and non-const this:
void ajouteFigure(Figures* f)
Then you should call it passing a pointer to a Figures object, i.e. created with a new expression:
s.ajouteFigure(new Cercle(1.1));
That being said, this code seems pointless. You're adding the pointer as many times as you have elements in the vector (which is always 0 in the example you provided).
Using raw pointers is also unadvised, you should use smart pointers like std::unique_ptr, although that would break the current code.
Consider this, less improper, example:
class Dessin
{
private:
vector<unique_ptr<Figures>> T;
public:
void ajouteFigure(unique_ptr<Figures> f)
{
T.push_back(move(f)); // just once
}
};
and at the call site:
Dessin s;
s.ajouteFigure(make_unique<Cercle>(1.1)); // C++≥14
or, if you can't use C++14:
Dessin s;
s.ajouteFigure(unique_ptr<Figures>(new Cercle{1.1}));
Just to add to this, I think you would be better to make it a template function and create the right object inside the function with arguments to the constructor passed as function parameters.
This way you don't have to create a std::unique_ptr or use new every time you call the function.
Here's a basic implementation:
class Dessin{
public:
template<typename T, typename ... Args>
void ajouteFigure(Args &&... args){
figures.emplace_back(new T(std::forward<Args>(args)...));
}
private:
std::vector<std::unique_ptr<Figures>> figures;
};
Then using the class is less error-prone:
int main(){
Dessin d;
d.ajouteFigure<Cercle>(1.1);
}

A circular dependency involving comparison functors

Suppose that we need to store information about labeled e-mail messages. Each message can be assigned many labels. Also, we would like to be able to quickly retrieve all messages assigned to a given label. Here is my design:
class Message;
class Label {
public:
...
private:
std::string name_;
std::set<std::shared_ptr<Message>,
std::function<bool(...)>> messages_; // Message is incomplete!
};
class Message {
public:
...
private:
std::string title_;
std::set<Label *,
std::function<bool(...)>> labels_; // fine
};
Each label stores the set of messages to which the label is assigned. Since this set needs to be searchable by the message title, we pass std::function for comparison as the second template parameter of std::set. The Problem: this function object needs to be able to access the Message's members. However, Message is an incomplete type at this point.
The situation cannot be fixed by putting the definition of Message before the definition of Label, because then we would have a similar problem with std::function passed to the set of labels (the line commented as being fine in the above code), which needs to be searchable by label name.
Is there a fix or a better design for this?
First, a way to map a projection into an ordering:
template<class F>
struct order_by_t {
F f;
using is_transparent = std::true_type;
template<class Lhs, class Rhs>
auto operator()(Lhs&& lhs, Rhs&& rhs)const
-> decltype (
static_cast<bool>(f(std::declval<Lhs>()) < f(std::declval<Rhs>())
)
{
return f(std::forward<Lhs>(lhs)) < f(std::forward<Rhs>(rhs));
}
};
template<class F>
order_by_t<std::decay_t<F>> order_by(F&& f) {
return {std::forward<F>(f)};
}
A projection takes a type X and "projects" it onto a type Y. The trick here is that the type Y is the type of the field that we want to order our Xs by (in this case, a string, and the projection takes X to the name of X).
This means all we have to do is define the projection (the mapping from our type, to the part of the type we want to order it by), and then feed it to order_by_t and it will generate an ordering function for us.
order_by_t seems stateful, but it doesn't have to be. If F is stateless, so can order_by_t be! Stateless means we don't have to initialize the F, and we can just use it, and also can lead to the compiler understanding the code better (tracking state is hard for compilers, stateless things are easy to optimize).
Or, in short, stateless is better than stateful. Here is a stateless type that wraps a function call:
template<class Sig, Sig* f>
struct invoke_func_t;
template<class R, class...Args, R(*f)(Args...)>
struct invoke_func_t<R(Args...), f> {
R operator()(Args...args)const {
return f(std::forward<Args>(args)...);
}
};
Example use:
void println( std::string const& s ) {
std::cout << s << '\n';
}
using printer = invoke_func_t< void(std::string const&), println >;
and now printer is a type that any instance of it will call println when you use its operator(). We store the pointer-to-println in the type of printer, instead of storing a copy of the pointer inside of it. This makes each instance of printer stateless.
Next, a stateless order_by that wraps a function call:
template<class Sig, Sig* f>
struct order_by_f:
order_by_t< invoke_func_t<Sig, f> >
{};
which is one line, a side effect of the above being pretty polished.
Now we use it:
class Message; class Label;
// impl elsewhere:
std::string const& GetMessageName( std::shared_ptr<Message> const& );
std::string const& GetLabelName( std::shared_ptr<Label> const& );
class Label {
private:
std::string name_;
using message_name_order = order_by_f<
std::string const&(std::shared_ptr<Message> const&),
GetMessageName
>;
std::set<std::shared_ptr<Message>, message_name_order > messages_;
};
where I jumped through a bunch of hoops to make it clear to the std::set that we are ordering by calling GetMessageName and calling < on the returned std::string const&s, with zero overhead.
This can be done simpler more directly, but I personally like each of the onion layers I wrote above (especially order_by).
The shorter version:
class Message;
bool order_message_by_name( std::shared_ptr<Message> const&, std::shared_ptr<Message> const& );
class Label {
private:
std::string name_;
std::set<std::shared_ptr<Message>,
bool(*)(std::shared_ptr<Message>const&, std::shared_ptr<Message>const&)
> messages_; // Message is incomplete!
Label(std::string name):name_(std::move(name)),
messages_(&order_messages_by_name)
{}
};
where we store a function pointer in our set that tells the class how to order it.
This has run time costs (the compiler will have difficulty proving that the function pointer always points to the same function, so will have to store it and dereference it on each ordering call), forces you to write order_messages_by_name (an ugly specific-purpose function), and has maintenance costs (you have to prove that the function pointer never changes whenever you think about that set).
Plus, it doesn't give you the cool order_by function, which you'll love every time you want to sort a std::vector by anything except <.

Uses of pointers non-type template parameters?

Has anyone ever used pointers/references/pointer-to-member (non-type) template parameters?
I'm not aware of any (sane/real-world) scenario in which that C++ feature should be used as a best-practice.
Demonstation of the feature (for pointers):
template <int* Pointer> struct SomeStruct {};
int someGlobal = 5;
SomeStruct<&someGlobal> someStruct; // legal c++ code, what's the use?
Any enlightenment will be much appreciated!
Pointer-to-function:
Pointer-to-member-function and pointer-to-function non-type parameters are really useful for some delegates. It allows you to make really fast delegates.
Ex:
#include <iostream>
struct CallIntDelegate
{
virtual void operator()(int i) const = 0;
};
template<typename O, void (O::*func)(int)>
struct IntCaller : public CallIntDelegate
{
IntCaller(O* obj) : object(obj) {}
void operator()(int i) const
{
// This line can easily optimized by the compiler
// in object->func(i) (= normal function call, not pointer-to-member call)
// Pointer-to-member calls are slower than regular function calls
(object->*func)(i);
}
private:
O* object;
};
void set(const CallIntDelegate& setValue)
{
setValue(42);
}
class test
{
public:
void printAnswer(int i)
{
std::cout << "The answer is " << 2 * i << "\n";
}
};
int main()
{
test obj;
set(IntCaller<test,&test::printAnswer>(&obj));
}
Live example here.
Pointer-to-data:
You can use such non-type parameters to extend the visibility of a variable.
For example, if you were coding a reflexion library (which might very useful for scripting), using a macro to let the user declare his classes for the library, you might want to store all data in a complex structure (which may change over time), and want some handle to use it.
Example:
#include <iostream>
#include <memory>
struct complex_struct
{
void (*doSmth)();
};
struct complex_struct_handle
{
// functions
virtual void doSmth() = 0;
};
template<complex_struct* S>
struct csh_imp : public complex_struct_handle
{
// implement function using S
void doSmth()
{
// Optimization: simple pointer-to-member call,
// instead of:
// retrieve pointer-to-member, then call it.
// And I think it can even be more optimized by the compiler.
S->doSmth();
}
};
class test
{
public:
/* This function is generated by some macros
The static variable is not made at class scope
because the initialization of static class variables
have to be done at namespace scope.
IE:
class blah
{
SOME_MACRO(params)
};
instead of:
class blah
{
SOME_MACRO1(params)
};
SOME_MACRO2(blah,other_params);
The pointer-to-data template parameter allows the variable
to be used outside of the function.
*/
std::auto_ptr<complex_struct_handle> getHandle() const
{
static complex_struct myStruct = { &test::print };
return std::auto_ptr<complex_struct_handle>(new csh_imp<&myStruct>());
}
static void print()
{
std::cout << "print 42!\n";
}
};
int main()
{
test obj;
obj.getHandle()->doSmth();
}
Sorry for the auto_ptr, shared_ptr is available neither on Codepad nor Ideone.
Live example.
The case for a pointer to member is substantially different from pointers to data or references.
Pointer to members as template parameters can be useful if you want to specify a member function to call (or a data member to access) but you don't want to put the objects in a specific hierarchy (otherwise a virtual method is normally enough).
For example:
#include <stdio.h>
struct Button
{
virtual ~Button() {}
virtual void click() = 0;
};
template<class Receiver, void (Receiver::*action)()>
struct GuiButton : Button
{
Receiver *receiver;
GuiButton(Receiver *receiver) : receiver(receiver) { }
void click() { (receiver->*action)(); }
};
// Note that Foo knows nothing about the gui library
struct Foo
{
void Action1() { puts("Action 1\n"); }
};
int main()
{
Foo foo;
Button *btn = new GuiButton<Foo, &Foo::Action1>(&foo);
btn->click();
return 0;
}
Pointers or references to global objects can be useful if you don't want to pay an extra runtime price for the access because the template instantiation will access the specified object using a constant (load-time resolved) address and not an indirect access like it would happen using a regular pointer or reference.
The price to pay is however a new template instantiation for each object and indeed it's hard to think to a real world case in which this could be useful.
The Performance TR has a few example where non-type templates are used to abstract how the hardware is accessed (the hardware stuff starts at page 90; uses of pointers as template arguments are, e.g., on page 113). For example, memory mapped I/O registered would use a fixed pointer to the hardware area. Although I haven't ever used it myself (I only showed Jan Kristofferson how to do it) I'm pretty sure that it is used for development of some embedded devices.
It is common to use pointer template arguments to leverage SFINAE. This is especially useful if you have two similar overloads which you couldn't use std::enable_if default arguments for, as they would cause a redefinition error.
This code would cause a redefinition error:
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
void foo (T x)
{
cout << "integral";
}
template <typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void foo (T x)
{
cout << "floating";
}
But this code, which utilises the fact that valid std::enable_if_t constructs collapse to void by default, is fine:
// This will become void* = nullptr
template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
void foo (T x)
{
cout << "integral";
}
template <typename T, std::enable_if_t<std::is_floating_point<T>::value>* = nullptr>
void foo (T x)
{
cout << "floating";
}
Occasionally you need to supply a callback function having a particular signature as a function pointer (e.g. void (*)(int)), but the function you want to supply takes different (though compatible) parameters (e.g. double my_callback(double x)), so you can't pass its address directly. In addition, you might want to do some work before and after calling the function.
It's easy enough to write a class template that tucks away the function pointer and then calls it from inside its operator()() or some other member function, but this doesn't provide a way to extract a regular function pointer, since the entity being called still requires the this pointer to find the callback function.
You can solve this problem in an elegant and typesafe way by building an adaptor that, given an input function, produces a customised static member function (which, like a regular function and unlike a non-static member function, can have its address taken and used for a function pointer). A function-pointer template parameter is needed to embed knowledge of the callback function into the static member function. The technique is demonstrated here.