I'm working on a project using interface based programming. The first part of this is for context just in case someone says I'm doing something completely wrong or has a different approach that fixes my issue.
I have a container class that includes several abstract interface classes. These define functions that return data I need.
This container class has a vector of parts that do not know about the container class, and therefore does not include the interface headers.
Every part is an object of the same type. When creating these objects, it passes a function pointer as an argument to the constructor of the child objects. This argument is a pointer to a function defined in one of the interface classes.
I'm trying to pass a pointer using &iTheInterfaceClass::theDataFunction to a constructor expecting U16(*pDataFunction)().
This results in the error
cannot convert 'U16 (iTheInterfaceClass::*)() {aka short unsigned int (iTheInterfaceClass::*)()}' to 'U16 (*)() {aka short unsigned int (*)()}' in initialization
If the parts include the .h file, I can get this to work, as I just match the prototype to include the namespace in the constructor. However, this breaks my abstraction. If each part includes a different interface, I have to create individual classes for each, even though the functionality is identical.
Is there anyway to get the prototypes to match without completely readjusting my strategy here?
As you've said yourself, your constructor expects the following type (excluding names):
U16 (*)()
However, you are trying to pass the following type:
U16 ( iTheInterfaceClass::* )()
Your constructor accepts free functions and class functions that are static, but you are trying to pass a non-static member function.They are not of the same type.
You could provide an overload for your constructor that takes in a member function as well as a reference or pointer to the object that the member function will be called on.
It could look something like:
public:
typedef U16( iTheInterfaceClass::*MemberFunctionPtr )();
MyContainer( iTheInterfaceClass& member, MemberFunctionPtr function ) : ... { ... }
Assuming you stored that information in some variables somewhere in the class, you could then call that function like so:
( member.*function )();
Where member is the variable that holds a reference to the object that you want to call the function on and function is the variable which holds the pointer to said member function.
Related
I've tried various solutions on SO to solve this problem, yet I must be doing something wrong.
I have several classes where methods in each of the classes have the same method signature:
typedef int (*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> ¶ms);
And an example class having some method using that signature:
class StaticContentController {
public:
int handleStaticContentRequest(const std::string &data, const std::unordered_map<std::string, std::string> ¶ms) {
return 1;
}
}
Now I try to create a map of pointers to member functions:
std::map<std::string, ControllerMethod> operations;
operations.emplace("staticContent", &StaticContentController::handleStaticContentRequest);
std::string d("test.txt");
ControllerMethod f = operations["staticContent"];
auto s = ((_staticContentController).*f)(d, pooledQueries); // <- compile error here
but calling the method gives the compile error
Right hand operand to .* has non-pointer-to-member type 'web::server::ControllerMethod'
What am I missing?
Update:
I now have an empty Controller base class which other controller classes inherit from:
namespace web { namespace server {
class Controller {
};
typedef ControllerResponse (Controller::*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> ¶ms);
}}
Now I'm getting the following error at operations.emplace():
No matching constructor for initialization of 'std::__1::pair<const std::__1::basic_string<char>, web::server::ControllerResponse
Updated answer
You're trying to use two different paradigms here, and they aren't really compatible with one another. If I interpret your edit correctly, you're trying to create a map of functions that call into other classes, and you want to declare this map as a set of function pointers.
Function pointers are an assembly level construct, exposed by C. The syntax reflects this - and getting a C++ class to conform to this is not possible without help - namely, adding a context pointer parameter that is associated with every function pointer, and converting the context pointer to a class instance to call the member function.
So, how do we fix the problem?
In both of the next approaches, we need a context object associated with the function table. This involves creating a structure to hold the member function and the context:
template<typename T> struct FunctionTableEntry
{
ControllerMethod Function;
T* Context;
};
and our function pointer becomes the following:
typedef ControllerResponse (T::*ControllerMethod)(const std::string &data, const StringMap ¶ms);
Here, StringMap is a typedef for std::unordered_map<std::string, std::string>.
Our main problem now comes with removing the template parameter T, as we can't make maps of runtime defined templates (a template who's type will only be known at run time).
There are two main approaches to take in resolving this, and both have issues that will need to be considered. The first is to perform C style type erasure with pointers and very careful association. The second is to abandon function pointers in favor of C++ function objects.
C-Style Type Erasure
This option involves using C-style casts to convert the class instance pointer to its base class type, the member function pointer to the type expected by the function declaration, and then making the call as though the base class defines the method. This requires the use of pointers, and cannot be done without them.
To do this, our FunctionTableEntry structure changes to the following:
struct FunctionTableEntry
{
ControllerMethod Function;
Controller* Context;
}
and our function pointer to:
typedef ControllerResponse (Controller::*ControllerMethod)(const std::string &data, const StringMap ¶ms);
To add a new entry, we do the following:
std::map<std::string, FunctionTableEntry> operations;
FunctionTableEntry Entry;
Entry.Function = (ControllerMethod)&StaticContentController::handleStaticContentRequest;
Entry.Context = (Controller*)&_staticContentController;
operations.emplace("staticContent", Entry);
And to call it:
FunctionTableEntry f = operations["staticContent"];
auto s = ((f.Context)->*f.Function)(d, pooledQueries);
This method suffers from a few drawbacks - first, you have no other choice but to use pointers to refer to your controller objects - casting will not function properly otherwise. You can make this a bit more C++ friendly with std::shared_ptr, but otherwise, there is no way to replace it. This also means you need to carefully manage the lifetime of your controller objects. If they get freed while the function table is still referencing them you will almost certainly crash the system.
Second, the casting can cause issues with complex inheritance hierarchies. This method only works if (Controller*)_staticContentController == _staticContentController, i.e. casting to the base class gives the same numerical pointer value. Otherwise, the called method will fail as it will not be able to properly reference its local data.
This method has the advantage of being quite fast, however. There is no function overhead besides the table lookup, and the generated assembly is not much more than just calling the function normally. It is also runtime independent - so long as the equality expression above is true with all users of the controller system, anyone with a C++ compiler can create a new controller and this system will be able to call their functions, even if they use a completely different runtime library.
Additionally, if you know the controller instance is going to be used with multiple functions, you can modify the structure to provide a map of functions associated with one Context value, allowing you to reduce some of the memory overhead. This may not be possible with your design, but it's worth looking into if memory is a concern.
C++ Function Objects
The second solution is to completely do away with C-style function pointers altogether and use std::function. Since std::function can contain instance data as part of itself, and can be placed into a map, this allows you to std::bind a member function, creating a partially specified function call (I believe in functional programming this is what's called a closure).
In this case, there is no FunctionTableEntry structure - instead we use the following:
typedef std::function<ControllerResponse(const std::string&, const StringMap&)> ControllerMethod;
To add a new method, we do the following:
std::map<std::string, ControllerMethod> operations;
operations.emplace("staticContent", std::bind(&StaticContextController::handleStaticContentRequest, &_staticContentController, std::placeholders::_1, std::placeholders::_2);
This creates a closure that calls the member function with the required controller instance.
To call this, we do the following:
std::string d("test.txt");
ControllerMethod f = operations["staticContent"];
auto s = f(d, pooledQueries);
C++ function objects override operator (), which allows them to work as though they were static functions.
This method allows for both member functions and static functions to exist in the same map. It also allows for complex inheritance hierarchies to occur, as there is no casting to make things function - everything occurs with template functions.
The downside to this method is you still need to deal with object lifespan - the content controller objects cannot be destroyed until after the function map has been cleared. In addition, there is some overhead due to the use of std::function with placeholder parameters (though that likely depends on the runtime library in use, my tests have shown it generates a whole lot more code in x86-64 GCC 9.3).
This method also is not runtime independent - whatever runtime you choose to use here must also be used by every programmer that uses this code, otherwise incompatibilities in the way each library creates and stores std::function will cause strange failures. This means no compiler mixing - if you used MSVC 2019 to build the API, everyone else who uses this library must use MSVC2019 to build their controller component. If you aren't providing an API here, then this is not an issue.
Original answer
Your function pointer declaration is wrong - pointers to members have a different syntax to the normal function pointer typedef.
A normal function pointer uses the syntax you have currently:
typedef int (*foo)(int x, int y);
A pointer to member function typedef looks like this:
typedef int (SomeClass::*foo)(int x, int y);
The SomeClass:: section is required as pointers to members have an additional parameter to them, called this. In C++, the this pointer is passed as the first argument to the function, which makes the function declaration different (as the actual assembly code needed to call the function is different, see MSVC generated assembly for a real world example).
To solve the issue, you need to provide a base class that can be used to declare the typedef, then inherit from that class to allow the method to be called. This is effectively identical to using inheritance, unless you have multiple methods in the same type that have the same signature, but do different things.
The DirectX 11 Effects framework uses this exact paradigm to avoid branching when configuring different shader types in the graphics pipeline - see here, at line 590.
As pointed out, the type of a non-static member function of the class StaticContentController is not:
typedef int (*ControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> ¶ms);
Instead, it is:
typedef int (StaticContentController::*StaticContentControllerMethod)(const std::string &data, const std::unordered_map<std::string, std::string> ¶ms);
This was your initial error.
This makes sense as you need an instance to call the member function, and the instance has a type as well. And it makes sense that if you have a Base::*Function pointer, you can call it with an instance of a class publicly and unambiguously derived from Base, because a derived pointer can be converted implicitly to a base pointer.
It also makes sense that you cannot assign a Derived::*Function pointer to a Base::*Function pointer because the result could be called with any Base instance, which need not be a Derived instance. This was the error in the question update.
In this very limited circumstance, C++ behaves completely logically.
With the modification to the correct type, your snippet will compile:
std::map<std::string, StaticContentControllerMethod> operations;
operations.emplace("staticContent",
&StaticContentController::handleStaticContentRequest);
std::string d("test.txt");
StaticContentControllerMethod f = operations["staticContent"];
auto s = ((_staticContentController).*f)(d, pooledQueries); // <- works
So presumably your actual question is how to store in this map member function pointers for multiple classes and not just StaticContentController. But that is the wrong question. You have to have the instance (_staticContentController) to invoke the member function pointer, so you already know the type.
So maybe you want to ask how to erase the type. One way is storing something that doesn't require an instance: for that, use std::function as the mapped type and bind the instance when inserting into the map. That would work and be straightforward if you have the controller at the time the map is created. A second way is using a type erasing type like std::any for the mapped type, and use any_cast at the point of use to return it to its initial type. A third way is to use a common base class with virtual functions which are overridden in your classes. Since the virtual functions can be called with a base pointer, you can store member function pointers of the base class.
Alternatively, maybe you want to ask how to have a type-indexed collection: the type is known at lookup time (because you have an instance) and you need to lookup a value whose type (member function pointer) depends on the "key" type.
The simplest way to do this is to have templated classes, and let the compiler handle the mapping:
template<typename T>
struct operations {
static std::map<std::string, void (T::*)(etc.)> pointers;
};
// use:
operations<StaticContentController>::pointers["staticContent"];
Another version of type-indexing might have the following interface:
template<template<typename> typename Value>
class type_keyed_map
{
public:
template<typename T>
void insert(std::unique_ptr<Value<T>> value);
template<typename T>
auto find() -> Value<T>*; // return null if not found
};
You can use a std::map in the implementation, but std::map does not allow multiple value types.
I am trying to implement a wrapper for a library called libumqtt. Libumqtt is a C library that uses libev to have callbacks for events from the MQTT protocol.
What I didn't realize until the other day is that I cannot pass a member function to a function that expects a normal, static function. This causes problems as I was planning on launching multiple instances of libumqtt to handle multiple connections at the same time.
My code is in C++ as that is the most convenient to use with the Godot's (a game engine) GDNative module.
While researching for either a way to sandbox multiple instances of a c library or to somehow get the pointers to work anyway, I found this answer. I do not understand this quote from the answer:
If you need to access any non-static member of your class and you need
to stick with function pointers, e.g., because the function is part of
a C interface, your best option is to always pass a void* to your
function taking function pointers and call your member through a
forwarding function which obtains an object from the void* and then
calls the member function.
What I am trying to do is setup callbacks that libev will use to send the data to the right instance of my object when it is handling potentially up to 500 or more connections simultaneously.
Will passing void* help me with my goals and how would I implement this? Also, how does a forwarding function work?
Edit: To Provide Code Example That Walnut Is Asking For
This example below comes from a version of my class that uses static functions. If I tried to use run this when the functions are not static, then I would get an error about not being able to pass in a member function in place of a regular function.
// Client.cpp
void Client::signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
ev_break(loop, EVBREAK_ALL);
}
// ...
void Client::do_connect(struct ev_loop *loop, struct ev_timer *w, int revents) {
//Godot::print("Attempt MQTT Start!!!\n");
//write_log("debug", "MQTT Wrapper - Attempt MQTT Start!!!");
struct umqtt_client *cl; // Move to Class Access (Private)?
cl = umqtt_new(loop, cfg.host, cfg.port, cfg.ssl);
if (!cl) {
//Godot::print("Failed To Create Client!!!\n");
//write_log("debug", "MQTT Wrapper - Failed To Create Client!!!");
start_reconnect(loop);
return;
}
//Godot::print("Setup Client Callbacks!!!\n");
//write_log("debug", "MQTT Wrapper - Setup Client Callbacks!!!");
// For StackOverflow: These cl->... lines do not work because of not being able to pass a member function as a regular function. These are the main callbacks I have trouble with.
// How do I convert from `void (libumqtt::Client::*)(struct umqtt_client *)` to `void (*)(struct umqtt_client *)`?
cl->on_net_connected = Client::on_net_connected; // Pass member function as a non-static object
cl->on_conack = Client::on_conack; // Pass member function as a non-static object
cl->on_suback = Client::on_suback; // Pass member function as a non-static object
cl->on_unsuback = Client::on_unsuback; // Pass member function as a non-static object
cl->on_publish = Client::on_publish; // Pass member function as a non-static object
cl->on_pingresp = Client::on_pingresp; // Pass member function as a non-static object
cl->on_error = Client::on_error; // Pass member function as a non-static object
cl->on_close = Client::on_close; // Pass member function as a non-static object
//Godot::print("MQTT Start!!!\n");
//write_log("debug", "MQTT Wrapper - MQTT Start!!!");
}
void Client::initialize() {
// For StackOverflow: These two lines cannot work in an object as libev expects signal_cb and do_connect to be regular functions. These callbacks are also necessary, but I am not sure how to handle this.
ev_signal_init(&signal_watcher, Client::signal_cb, SIGINT);
ev_timer_init(&reconnect_timer, Client::do_connect, 0.1, 0.0); // Fix Me - Make ev.h object
// ...
}
Edit: I should mention I am a noob at using C and C++. The most I've done in it before is testing a buffer overflow. So, if their's anything I am obviously doing wrong, I would appreciate the tip in the comments.
So the issue is that umqtt_client does not seem to provide any way of passing additional user data to the callback (the void* mentioned in your quote). It expects the callback to take just a pointer to the umqtt_client instance. (I may be wrong here, I am basing this just on a quick look at the source files.)
If your member functions don't actually access any non-static member of your class, then you can simply make them static. Then you can use them directly as normal function pointers.
Otherwise you need to obtain a pointer to your instance from the umqtt_client* pointer.
One way of doing this would be to maintain a static map between the pointers, e.g. in Client add a declaration:
static std::map<umqtt_client*, Client*> umqtt_client_map;
and insert into it when creating a Client (I will assume here that you actually maintain the cl pointer as class member of Client), preferably in Client's constructor:
umqtt_client_map[cl] = this;
Then in Client's destructor (or where ever the umqtt_client object is destroyed) erase the corresponding element from the map:
umqtt_client_map.erase(cl);
Then you can use a lambda looking like this to pass as callback:
cl->on_net_connected = [](umqtt_client* ptr){
umqtt_client_map[ptr]->on_net_connected();
};
Note that on_net_connected won't need the pointer as argument if it is a member of the class.
This also assumes that you make the class non-copyable and non-movable or that you implement the copy- and move-constructor and -assignment operators with the correct semantics of erasing and inserting into umqtt_client_map as well.
The library seems to offer a function umqtt_init instead of umqtt_new that doesn't allocate the umqtt_client object. If you use that instead you could do the following:
Wrap the umqtt_client in a small standard-layout class:
struct umqtt_client_wrapper {
umqtt_client cl; // must be first member!
Client* client;
static_assert(std::is_standard_layout_v<umqtt_client_wrapper>);
};
You would then use that as member of Client instead of umqtt_client* directly and initialize the umqtt_client* with umqtt_init) andclientwiththisinClient`'s constructor. Then you can use a cast in the lambda for the callback:
cl->on_net_connected = [](umqtt_client* ptr) {
reinterpret_cast<umqtt_client_wrapper*>(ptr)->client->on_net_connected();
};
Note that this depends on umqtt_client_wrapper being standard-layout and that umqtt_client* is its first member. Not following these rules will cause undefined behavior. The static_assert gives some assurance that at least part of it is not accidentally violated. It requires #include<type_traits> and C++17 in the form that I used here.
Again this requires special care to implement the copy- and move- special member functions of Client correctly or to delete them, but with this method no action in the destructor is required.
This approach is more performant than the other one and in principle you could avoid the extra Client pointer if you make sure that Client itself is standard-layout, but that is probably too restrictive and risky.
Another way, saving the extra indirection, is to use the wrapper as a base class of Client:
struct umqtt_client_wrapper {
umqtt_client cl; // must be first member!
static_assert(std::is_standard_layout_v<umqtt_client_wrapper>);
};
Then let Client inherit from umqtt_client_wrapper and you can use:
cl->on_net_connected = [](umqtt_client* ptr) {
static_cast<Client*>(reinterpret_cast<umqtt_client_wrapper*>(ptr))
->on_net_connected();
};
Note that here the first cast must be static_cast, otherwise you could easily cause undefined behavior.
The same remarks as before apply.
I'm trying to implement more flexibility in my numerics by allowing me to choose different forms of a mathematical function and vary their parameters through instantiating them as objects of a certain class. That class includes certain mathematical functions I may choose plus parameters that I can vary. The constructor of the class sets a member function pointer in the class to a member function according to what mathematical function I want. I want to solely use the pointer to call whatever function it points to by directly using the pointer in my routine.
However, that proved daunting as I didn't know that member function pointers require a certain syntax and seem to work somewhat differently from regular function pointers according to what I could gather. I've experimented quite a bit and constructed myself a minimal example shared below.
#include<iostream>
#include<string.h>
#include<cstdlib>
#include<stdio.h>
class Someclass
{
public:
// constructor to set pointer
Someclass(std::string);
// member function pointer to hold functions
void (Someclass::*fptr)();
// auxiliary function to call testfunction via pointer
void call ();
// testfunction
void foo();
};
// testfunction
void Someclass::foo()
{
printf("foo says hi! \n");
}
// call via specific function
void Someclass::call()
{
(this->*fptr)();
}
// constructor
Someclass::Someclass(std::string name)
{
if(name=="foo")
{
this->fptr = &Someclass::foo;
}
}
int main()
{
Someclass someobject("foo");
someobject.foo(); // direct testfunction call: Works OK
someobject.call(); // call via auxiliary function: Works OK
//(someobject.*fptr)(); // direct pointer dereferencing: Gives Error
return(EXIT_SUCCESS);
}
It shows that I can access the pointer by use of another member function that just calls whatever the pointer points to via use of a this pointer. However, I still can't seem to get the function call to work if I try to use the pointer directly in my main function through the line,
(someobject.*fptr)()
This particular expression leads to my compiler complaining about the scope and if I include the class scope, the compiler mentions invalid use of non-static members. Still, I'm confused as to why my implementation here doesn't work and if it does, how the proper syntax in my problem would be and why that has to be so.
Any insights would be really appreciated.
fptr is a member of the object, not a variable local to main. In such respect member function pointers behave exactly the same as all other variable types. You were so close, and just need to qualify the function pointer name with the object name:
(someobject.*(someobject.fptr))();
The reasons for this is .* indicates a pointer to member function and does not directly reference the members of an object like the . and .-> operators. Since fptr is a member of Someclass and not a local variable you need to reference it directly like so
(someobject.*someobject.fptr)();
AFAIK, in C++, invoking another member function within a member of function of the same class should not require the "this" prefix as it is implicit. However, in the specific case of using function pointers, the compiler requires it. The following code compiles correctly only if I include the "this" prefix for the call via func pointer -
When function pointers are used can the compiler deduce when it points a member func of the same class?
class FooBar
{
private:
int foo;
public:
FooBar()
{
foo = 100;
}
int GetDiff(int bar)
{
return abs(foo - bar);
}
typedef int(FooBar::*MyFuncPtr)(int);
void FooBar::Bar()
{
MyFuncPtr f = &FooBar::GetDiff;
(this->*f)(10);
GetDiff(10);
}
};
It's required, because member function pointers (which are not the same thing as function pointers) are not bound, and you can use them with different objects.
(this->*f)(10);
(foo.*f)(10);
// etc.
When you invoke an instances member function the this pointer is implicitely put to the function parameters. Thus you need to specify this also when invoking that function via a function pointer.
f isn't a member of the class, but a local variable, you could also specify another instance pointer instead of this, so the compiler can't deduce that. Same for member function pointers as class member variables.
The simple question is that it is a matter of language design and the language was designed this way.
Inside a member function, and to ease the common syntax when the compiler encounters an identifier it performs lookup starting from this class (plus ADL on the arguments), and if the lookup finds an unambiguous non-static member of this type (or of a base type) then the compiler will inject this-> for you (that is, applies operator-> to the this pointer).
In the case of a pointer to member the process is quite different. The pointer (which is not really a pointer, but for the sake of argument) is found by lookup, but it is your responsibility to provide the object on which it will be called and use the appropriate operator (either .* for calling a pointer to member on a reference, or ->* for calling the member on a pointer).
Note that the operators that are called are different, and that the process is different altogether (in one case lookup finds a member, in the other it finds a variable that happens to be pointer-to-member), but the most important part is that calling pointers to members is infrequent enough, and calling them on this is even less frequent that it does not not to warrant an exemption on the syntax for a small use case.
f isn't a member of FooBar. So if you want to call f on an instance of FooBar, you have to tell it which instance.
In your example, f does contain a member of FooBar, but the compiler doesn't know that.
This happens because of the way the C++ runtime handles classes while you are not looking.
Basically it would be inefficient to store the function pointers in the instance, so the compiler builds a class specific table with function pointers that have the same arity as the member functions you defined and that get the this pointer passed at runtime (AFAIK visualc passes the pointer via ecx, I'm not entirely sure what happens on GCC)
So basically when you do
instance->foo(10);
You are telling the runtime to call function foo with the parameter 10 and pass (instance) as the this pointer, wich is why you have to specifically say which object it has to be called on.
i have made a sample example, in this i'm trying to pass a function as argument i am getting error, could you please help me
typedef void (*callbackptr)(int,int);
class Myfirst
{
public:
Myfirst();
~Myfirst();
void add(int i,callbackptr ptr)
{
ptr(i,3);
}
};
class Mysec
{
public:
Myfirst first_ptr;
Mysec();
~Mysec();
void TestCallback()
{
callbackptr pass_ptr = NULL;
pass_ptr = &Mysec::Testing;
first_ptr.add(2,&Mysec::Testing);
}
void Testing(int a,int b)
{
int c = a+b;
}
};
The type of the callback function you're passing as parameter is not defined as part of a class. You probably should define Testing as static.
You are geting an error because you are pointing to a member function. Pointers to member functions are different. See here:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.1
A member function needs to know what instance it is working with (the this pointer) so it can't be called like any other function. If you moved the callback function out of the class (or made it static, which is similar to moving it out of the class) you could call it like any other function.
A more modern way of doing this is to use functors, e.g. boost::function and something like boost::bind :
C++ Functors - and their uses
how boost::function and boost::bind work
Those can hide the difference between member and global functions.
You are trying to access a member function pointer here, using a simple function pointer typedef, which will not work. Let me explain.
When you write a normal, non-member function (similar to C), the function's code actually exists in a location indicated by the name of the function - which you would pass to a function pointer parameter.
However, in the case of a member function, all you have is the class definition; you don't have the actual instance of the class allocated in memory yet. In such a function, since the this pointer is not yet defined, any reference to member variables wouldn't make sense, since the compiler doesn't have enough information to resolve their memory locations. In fact, member function pointers are not exact addresses; they encode more information than that (which may not be visible to you). For more, read Pointers to Member Functions.