I have a class with an array who's size is specified in the constructor. The class also stores a pointer to a function that takes a pointer as a parameter which, when called, will be set to point to the array. I also have a "bind" function which sets the function pointer equal to some other function passed in as a parameter. This allows me to bind arbitrary functions who's parameters will contain the array. It looks like this:
template <typename T>
class MyClass{
public:
MyClass(int s) : size(s) { arr = new T[size]; }
MyClass() { delete[] arr; }
virtual inline void bindFunc(void(*func)(T[])) { fn = func; } //types match, ok
inline void callFunc(){fn(arr);}
/*Yes, I know I need a size parameter to correctly
iterate over arr, I took out this info to help make things more clear, just pretend
arr is null terminated and the bound fn function knows how to correctly handle it*/
private:
const int size;
T arr[];
void(*fn)(T[]);
};
This works fine and all, but the point of using arrays (or any container type) was so classes that inherit from MyClass can specify an explicit size. I then planned to (somehow) override the bindFunc function to take a pointer to a function that has an explicit number of separate parameters instead of a pointer to a function with an array of parameters. This is simply to clean up the syntax and make the derived class hide implementation. It would look something like this:
class derived: public MyClass<double> {
public:
derived() : MyClass(2) {}
inline void bindFunc(void(*func)(double, double)) { fn = func; } //error, type mismatch, obviously
};
The error occurs where fn = func because fn is a pointer to a function that takes an array(pointer) as a parameter and func is a pointer to a function that takes 2 doubles as parameters. This is the crux of the problem that I do not know how to fix.
Of course, in this snippet I slimmed down the code a bit to only contain the relevant parts and renamed everything to better portray my problem. If it helps, the original purpose of the class was to store state information passed in from GLFW's callback functions. The derived class(es) were supposed to hold scroll and mouse position info respectively (1 element for scroll position, 2 elements for mouse X/Y position, hence the array who's size is set in the derived class' constructor.) The base class also had functions for calculating other things such as deltas that any other imaginable type of variable input would find useful, hence the hierarchy abstraction. This was all meant to simplify input handling and would've looked something like this when being utilized:
void mouse_callback(GLFWwindow*, double, double);
glfwSetCursorPosCallback(window, mouse_callback);
MyClass *MouseInput = new derived;
void mouseFunction(double x, double y){ //takes 2 doubles instead of array of doubles of size 2
if(x > 0.5)
//do something
if(y < 0.5)
//do something else
}
void main(){
MouseInput->bindFunc(mouseFunction);
MouseInput->callFunc();
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
MouseInput->setInfo(xpos, ypos);
/*this function is not shown in the code above, but it basically sets
MouseInput->arr's variables and calls a base class' calculation function
to calculate extra info such as the aforementioned deltas*/
}
I'm not sure if what I want is possible, but I'm interested in learning more about it or a more correct design pattern. I've tried fiddling around with <functional> functions, but I couldn't come up with anything myself. It feels like there would be a feature to the language that would make something like this possible, which is why I cared to type up this question to begin with.
Most of what I experiment with in C++ is for learning and I know my methods might be a little insane for what I'm trying to accomplish, but the hope is it will lead to being a better programmer. Thanks for your insight in advance!
If you use std::function instead of raw function pointers, you can use a lambda to translate the arguments in any way you want:
template <typename T>
class MyClass{
std::function<void(T[])> fn;
public:
virtual inline void bindFunc(void(*func)(T[])) { fn = func; } //types match, ok
virtual inline void bindFunc(void(*func)(T, T)) {
fn = [func](T args[]) { func(args[0], args[1]); }; }
for more flexibility, you can make the func argument a std::function as well
Related
I have my fancyFunction which takes a set of elements implementing interface A. The function does a complicated analysis of those elements, based on properties read through interface A. During this analysis, it will call methods of a Consumer c which will take the elements as arguments.
The Consumer is designed to take arguments of a specific type which has absolutely nothing to do with A.
You could imagine that A is an abstraction for edges in a graph. The graph is analyzed in fancyFunction and - for example - every time the function "crosses" an edge, it will send that edge to a Consumer which prints additional information stored in the edge that has nothing to do with it being an edge.
The code given below would of course not compile in a typed language (particularly C++), but leaving out the types (Matlab, Python), the code would work.
To make it work in a typed language (particularly C++), I see two options:
Declare the function as
template <class CONSUMER>
void fancyFunction(A[] setOfAs, CONSUMER c){ ... }
Declare operation1 and operation2 to take the most general object and then do a downcast in the implementation.
What do you recommend to do in that situation? (As far as I see, the visitor pattern is NOT an option.)
Full code outline (I did not use C++ in a while, so please excuse if there are minor syntactical mistakes.):
void fancyFunction(A[] setOfAs, Consumer* c){
// do fancy analysis of setOfAs by properties
// read through interface A
double x = setOfAs[i]->getX();
// call functions in c with arguments of setOfAs[j]
...
c->operationX(setOfAs[i]);
...
c->operationY(setOfAs[j]);
...
}
class A{
virtual double getX();
}
class Consumer{
virtual void operationX(??? x); // whoops, what type do we expect?
virtual void operationY(??? y); // whoops, what type do we expect?
}
class Consumer1{
void operationX(Obj1 x){ ... } // whoops, override with different type
void operationY(Obj1 y){ ... } // whoops, override with different type
}
class Consumer2{
void operationX(Obj2 x){ ... } // whoops, override with different type
void operationY(Obj2 y){ ... } // whoops, override with different type
}
class Obj1 : public A {};
class Obj2 : public A {};
void test(){
Obj1 o1[];
Obj2 o2[];
Callback1 c1;
Callback2 c2;
fancyFunction(o1, &c1);
fancyFunction(o2, &c2);
}
I believe the solution you're looking for is called the Visitor Pattern.
You don't want to manually cast each instance of object A in your fancy function, because that is a maintenance nightmare and a clear code smell.
On the other hand, what if each object automatically handled its own casting? That's the Visitor Pattern.
You begin by defining a new "Visit" function in your base class (A), taking your Consumer as its only argument:
class A
{
public:
virtual void Visit(Consumer& consumer) = 0;
}
You then implement this function for every inherited class, thusly:
class B : public A
{
public:
void Visit(Consumer& consumer)
{
consumer.DoOperation(this); // 'this' utomatically resolves to type B*
}
}
Each derived type now handles calling the appropriate operation overload, by passing the 'this' pointer to the provided Consumer instance. The 'this' pointer is automatically interpreted as the most specific type possible.
Looking back through your original example code, it appears you have each Consumer providing multiple operations, and only handling a single type. This pattern would likely require that you change this paradigm slightly: create a single Consumer for each operation, where each consumer provides overloads for every possible inherited type.
class ConsumerX
{
public:
void DoOperation(A* a) { /* ERROR! This is a base type. If this function is called, you probably need to implement another overload. */ }
void DoOperation(B* b) { /* Much better */ }
}
class ConsumerY
{
public:
void DoOperation(A* a) { /* ERROR! This is a base type. If this function is called, you probably need to implement another overload. */ }
void DoOperation(B* b) { /* Much better */ }
}
Then your implementation loop looks something like this:
ConsumerX consumerX; // Does Operation X for every type
ConsumerY consumerY; // Does Operation Y for every type
for(int x = 0; x < numElements, x++)
{
auto element = setOfAs[x];
element.Visit(consumerX); //Do operation X
element.Visit(consumerY); //Do operation Y
}
Clearly a case where templates are appropriate. I'd even question why your fancyFunction is insisting on base class A. It should just take a begin and end iterator. I wouldn't bother with a consumer either. Make that flexible too, just take any function.
In fact, I wouldn't even write a fancyFunction. It already exists:
std::for_each(o1.begin(), o1.end(),
[c1](Obj1 o) { double x = o.getX(); c1.operationX(o); c1.operationY(o); }
);
In C++:
I have an object I'll call Foo.
Foo performs statistical operations on a supplied data set. The first step of the process involves a fitting function, and a functional parameter can be supplied so that the user can specify the type of model being used.
The problem is that I now have a situation where the function parameter needs to have access to data that does not exist in Foo but rather in the object that is using Foo, which I will call Bar.
So Bar calls Foo to have Foo operate on Bar's data. Bar has a specific function it wants to use as the functional parameter but this function requires information specific to Bar.
I don't want to pass Bar because if I code Foo up to receive Bar, then every time I have a new object that needs additional info passed to Foo, I will have to adjust the Foo class to accept that object.
I don't want to modify the functional parameter input in Foo because then I'll have to modify the functional parameter input for every new usage case as well.
I considered using a base class I'll call StandardFunc. Then, via virtual methods, Bar could create an object called ModifiedFunc that derives from StandardFunc. It could override the StandardFunc's function and also supply the additional info as class parameters. This doesn't work either because to avoid slicing I have to type-cast ModifiedFunc to StandardFunc. This means that inside Foo I have to change the type-cast line for every new object name.
Can someone please point me in the right direction for how I can allow users to pass either a functional parameter alongside arbitrary parameters the function requires without having to recode the Foo class for every different usage case? I'm really stuck on this.
EDIT: pseudo code example:
class Foo
{
void processHandler(function)
void process();
void process(function);
void theUsualFunction(vector); //the default function used by process
vector vec;
};
void Foo::process()
{
processHandler(theUsualFunction);
}
void Foo::process(function f)
{
processHandler(f)
}
void Foo::processHandler(function f)
{
f(vec)
//do other stuff to vec
}
void Foo::theUsualFunction(vector v)
{
//default vec processor
}
class Bar
{
int x;
int y;
vector vec;
void theModifiedFunction(vector);
void callFooToProcess();
};
void Bar::theModifiedFunction(vector v)
{
//process v, but in a way that requires x and y
}
void Bar::callFooToProcess()
{
Foo foo;
foo.setVector(vec);
process(theModifiedFunction);
}
So this code is kind of an example of what I want to achieve, but it doesn't work as written. The reason is because I have no way of getting Bar::x and Bar::y to the function Foo::processHandler(function) without modifying the arguments for Foo::processHandler, and I don't want to do that because then every new class like Bar and every new theModifiedFunction that requires different data will require me to rewrite the arguments for processHandler.
This doesn't work either because to avoid slicing I have to type-cast ModifiedFunc to StandardFunc.
Slicing only occurs if you pass the argument by value. You should pass it as a pointer, that's how polymorphism is supposed to work.
Also, you can keep passing the argument by value if you make your class a template:
template<class Func>
class Foo {
void doStuff(Func func) {
...
}
}
Keep in mind though, that in this case Func has to be known at compile-time.
Although there may be other ways of handling this situation, I would suggest considering to have Bar contain Foo. This is called a has-a relationship [wiki]. The advantage of this is that you can use Foo as-is without modifying anything within Foo, as well as Bar need not pass around its private data. Hope the following code snippet would help you to understand the concept.
public class Bar
{
private Foo myFoo;
private int myInfo;
void a()
{
myFoo.doStuff(myInfo);
}
}
I am having difficulty getting my head around how to pass a class member function to a subclass (not derived).
My top level class is like this:
class CTop
{
public:
CTop();
int func1(void);
private:
CFnList* _funcList;
};
CTop::CTop():
_funcList(0)
{
_funcList = new CFnList();
_funcList->addFnPtrToList(0, &CTop::func1);
}
int CTop::func1(void)
{
// Does some stuff...
}
My function list class is like this:
class CFnList
{
public:
// Public functions
CFnList();
void addFnPtrToList(int index, int (*fn)(void));
private:
// Fn pointer list
typedef struct
{
int index;
int (*fn) (void);
}fn_list_t;
// function pointer list
QVector<fn_list_t> _fn_list;
};
So basically here I have an instance of class CTop and one of its members is a pointer to a class CFnList. CFnList pointer is instantiated in the constructor of CTop. Then I want to pass in a pointer to one of CTop's member functions to CFnList by calling the following line:
"_funcList->addFnPtrToList(0, &CTop::func1);"
I get issue (quite rightly) that addFnPtrToList does not take the parameters (int, (CTop::*)()). So the compiler knows this function is a certain member function and not just a generic (maybe static) function.
Is there a way to pass the a pointer to the member function into the sub-class? In my case I want the sub-class to be able to call this function. I am thinking I probably have to make static member functions or something, but the syntax is eluding me on how to do this.
All help / advise appreciated.
Fodder
CTop::func1 is a member function. &CTop::func1 is NOT a function pointer, it is a pointer to member (function). Those can not be mixed either in storing or calling. it is not compatible with int (*fn)(void), as the latter takes no arguments and the former requires an object that is passed as the hidden this.
For these reasons you can't have a simple but uniform facility. You either can go with simple function pointers, or pairs of PTM+object pointer, or use wrappers -- handmade or stock like boost::function fueled by boost::bind. If you have C++11 or TR1 you can use the std:: equivalents of the latter.
A declaration in the form:
int (*fn)(void)
cannot point to a member function. It can only point to a free function. Philispophically, this is because the calling conventions for member functions are different then that for free functions. Consider for example the need for a this pointer in the context of a member function call.
The syntax for declaring a pointer-to-member-function is like this:
int (CTop::*fn)(void)
There is an entire section in the C++ FAQ dedicated to member function pointers. Check it out.
You are passing the member function as if it were a regular function. That fails to include the 'this' reference to the class. In order to pass member functions, you have to be able to re-reference it from the original 'this'. Take a look at the following, instead.
typedef void (CTop::*OBJFNC)(args);
_funcList = new CFnList();
_funcList->addFnPtrToList(0, this, &CTop::func1);
void addFnPtrToList(int index, CTop* pobj, OBJFNC pfnc)
{ ... Store both ...
}
Now elsewhere you can execute it with the following.
(pobj->*pfnc)(args);
Here is the final solution, it uses a mixture of passing the instance of the object CTop and usage of template class for CFnList:
My top level class is like this (more or less the same except for the declaration of _funcList to includes the class type and to pass in the "this" to the constructor:
class CTop
{
public:
CTop();
int func1(void);
private:
CFnList<CTop>* _funcList;
};
CTop::CTop():
_funcList(0)
{
_funcList = new CFnList(this);
_funcList->addFnPtrToList(0, &CTop::func1);
}
int CTop::func1(void)
{
// Does some stuff...
}
My function list class is like this:
template<class T>
class CFnList
{
public:
// Public functions
CFnList(T *parent);
void addFnPtrToList(int index, int (T::*fn)(void));
private:
// Pointer to the parent (or owner is perhaps more correct)
T* _parent;
// Fn pointer list
typedef struct
{
int index;
int (T::*fn) (void);
}fn_list_t;
// function pointer list
QVector<fn_list_t> _fn_list;
};
// Constructor
template <class T>
CFnList<T>::CFnList(T *parent) :
_parent(parent),
_fn_list(0)
{
}
// addFnPtrToList:
template <class T>
void CFnList<T>::addFnPtrToList(int index, int (T::*fn)(void))
{
_fn_list.append((fn_list_t){index, fn});
}
So the major changes are:
1. Pass the CTop type in by using changing CFnList into a template.
2. Pass in the instance of the object CTop (so that the pointer to the function can be called) by passing "this" into the constructor and then template class stores it as a pointer to the given template type.... vio-la!...easy :o
Thanks to all who contributed :))
I need to store multiple types of a template class in a single vector.
Eg, for:
template <typename T>
class templateClass{
bool someFunction();
};
I need one vector that will store all of:
templateClass<int> t1;
templateClass<char> t2;
templateClass<std::string> t3;
etc
As far as I know this is not possible, if it is could someone say how?
If it isn't possible could someone explain how to make the following work?
As a work around I tried to use a base, non template class and inherit the template class from it.
class templateInterface{
virtual bool someFunction() = 0;
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction();
};
I then created a vector to store the base "templateInterface" class:
std::vector<templateInterface> v;
templateClass<int> t;
v.push_back(t);
This produced the following error:
error: cannot allocate an object of abstract type 'templateInterface'
note: because the following virtual functions are pure within 'templateInterface'
note: virtual bool templateInterface::someFunction()
To fix this error I made the function in templateInterface not a pure virtual by providing a function body, this compiled but when calling the function the overide is not used, but instead the body in the virtual function.
Eg:
class templateInterface{
virtual bool someFunction() {return true;}
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction() {return false;}
};
std::vector<templateInterface> v;
templateClass<int> i;
v.push_back(i);
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body
Is there any way to fix this so that the overridden function is used, or is there another workaround to store multiple template types in a single vector?
Why your code doesn't work:
Calling a virtual function on a value doesn't use polymorphism. It calls the function which is defined for the type of this exact symbol as seen by the compiler, not the runtime type. When you insert sub types into a vector of the base type, your values will be converted into the base type ("type slicing"), which is not what you want. Calling functions on them will now call the function as defined for the base type, since not it is of that type.
How to fix this?
The same problem can be reproduced with this code snippet:
templateInterface x = templateClass<int>(); // Type slicing takes place!
x.someFunction(); // -> templateInterface::someFunction() is called!
Polymorphism only works on a pointer or reference type. It will then use the runtime type of the object behind the pointer / reference to decide which implementation to call (by using it's vtable).
Converting pointers is totally "safe" with regard to type slicing. Your actual values won't be converted at all and polymorphism will work as expected.
Example, analogous to the code snippet above:
templateInterface *x = new templateClass<int>(); // No type slicing takes place
x->someFunction(); // -> templateClass<int>::someFunction() is called!
delete x; // Don't forget to destroy your objects.
What about vectors?
So you have to adopt these changes in your code. You can simply store pointers to actual types in the vector, instead of storing the values directly.
When working with pointers you also have to care about deleting your allocated objects. For this you can use smart pointers which care about deletion automatically. unique_ptr is one such smart pointer type. It deletes the pointee whenever it goes out of scope ("unique ownership" - the scope being the owner). Assuming the lifetime of your objects is bound to the scope this is what you should use:
std::vector<std::unique_ptr<templateInterface>> v;
templateClass<int> *i = new templateClass<int>(); // create new object
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector
v.emplace_back(new templateClass<int>()); // "direct" alternative
Then, call a virtual function on one of these elements with the following syntax:
v[0]->someFunction();
Make sure you make all functions virtual which should be possible to be overridden by subclasses. Otherwise their overridden version will not be called. But since you already introduced an "interface", I'm sure you are working with abstract functions.
Alternative approaches:
Alternative ways to do what you want is to use a variant type in the vector. There are some implementations of variant types, the Boost.Variant being a very popular one. This approach is especially nice if you don't have a type hierarchy (for example when you store primitive types). You would then use a vector type like std::vector<boost::variant<int, char, bool>>
Polymorphism only works through pointers or references. You'll
need the non-template base. Beyond that, you'll need to decide
where the actual objects in container will live. If they're all
static objects (with sufficient lifetime), just using
a std::vector<TemplateInterface*>, and inserting with
v.push_back(&t1);, etc., should do the trick. Otherwise,
you'll probably want to support cloning, and keep clones in the
vector: preferably with Boost pointer containers, but
std::shared_ptr can be used as well.
The solutions given so far are fine though be aware that in case you were returning the template type other than bool in your example , none of these would help as the vtable slots would not be able to be measured before hand. There are actually limits , from a design point of view , for using a template oriented polymorphic solution.
Solution nr. 1
This solution inspired by Sean Parent's C++ Seasoning talk. I highly recommend to check it out on youtube. My solution simplified a bit and the key is to store object in method itself.
One method only
Create a class that will invoke method of stored object.
struct object {
template <class T>
object(T t)
: someFunction([t = std::move(t)]() { return t.someFunction(); })
{ }
std::function<bool()> someFunction;
};
Then use it like this
std::vector<object> v;
// Add classes that has 'bool someFunction()' method
v.emplace_back(someClass());
v.emplace_back(someOtherClass());
// Test our vector
for (auto& x : v)
std::cout << x.someFunction() << std::endl;
Several methods
For several methods use shared pointer to share object between methods
struct object {
template <class T>
object(T&& t) {
auto ptr = std::make_shared<std::remove_reference_t<T>>(std::forward<T>(t));
someFunction = [ptr]() { return ptr->someFunction(); };
someOtherFunction = [ptr](int x) { ptr->someOtherFunction(x); };
}
std::function<bool()> someFunction;
std::function<void(int)> someOtherFunction;
};
Other types
Primitive types (such as int, float, const char*) or classes (std::string etc.) may be wrapped in the same way as object class do but behave differently. For example:
struct otherType {
template <class T>
otherType(T t)
: someFunction([t = std::move(t)]() {
// Return something different
return true;
})
{ }
std::function<bool()> someFunction;
};
So now it is possible to add types that does not have someFunction method.
v.emplace_back(otherType(17)); // Adding an int
v.emplace_back(otherType("test")); // A string
Solution nr. 2
After some thoughts what we basically done in first solution is created array of callable functions. So why not just do the following instead.
// Example class with method we want to put in array
struct myclass {
void draw() const {
std::cout << "myclass" << std::endl;
}
};
// All other type's behaviour
template <class T>
void draw(const T& x) {
std::cout << typeid(T).name() << ": " << x << std::endl;
}
int main()
{
myclass x;
int y = 17;
std::vector<std::function<void()>> v;
v.emplace_back(std::bind(&myclass::draw, &x));
v.emplace_back(std::bind(draw<int>, y));
for (auto& fn : v)
fn();
}
Conclusion
Solution nr. 1 is definitely an interesting method that does not require inheritance nor virtual functions. And can be used to other stuff where you need to store a template argument to be used later.
Solution nr. 2, on the other hand, is simpler, more flexible and probably a better choice here.
If you're looking at a container to store multiple types, then you should explore boost variant from the popular boost library.
Is it possible to pass different objects as argument for 1 function, not making 3 functions
i.e
void someFunction(Object o) {
//working with object, all that objects have same fields to work with
// i.e. all objects have x, y fields and this function is working with it
}
Player pl;
Item itm;
Block bl;
someFunction(pl);
someFunction(itm);
someFunction(bl);
Maybe it can be done using templates or what?
I dont want to make 3 functions with same code for different objects
Yes, using templates:
template<class Type> void someFunction(const Type& o) {
//working with object, all that objects have same fields to work with
// i.e. all objects have x, y fields and this function is working with it
}
Note that you probably will prefer to pass o by const reference, not by value. I have done this here.
Yes, a template should work:
template <typename T>
void someFunction(T & o)
{
// use o.x, o.y, o.z
}
You can pass by reference or const-reference, depending on whether you want to modify the original object or not.
Templates can be used as an alias for a class of types. The following will allow any type to pass through the parameters of f.
template <typename T> void f(T & t) {
// ...
}
A template should work, but without taking SFINAE into account, you cannot assure that all the given objects have some fields.
Another solution could be inheritance here some sample code:
struct Foo
{
int x;
int y;
};
struct Bar: public Foo
{
int another_x;
};
struct Baz: public Foo
{
int another_y;
};
void someFunction(const Foo &foo)
{
std::cout << foo.x << '\n';
std::cout << foo.y << '\n';
};
With this approach, you can assure that all the given objects have the required members.
You can do this with templates or polymorphism (probably a parent interface with virtual methods to get and set relevant fields).
Templates will work and probably be well optimized, but will not allow new objects to be passed in later, regardless of whether they have the same fields. You will be able to compile new code and new objects to use the template functions, but existing calls will be stuck with a single type.
Using a parent interface and virtual methods, then making your function call those methods (presumably getters and setters) to handle the field manipulation will provide more freedom later, at the expense of slightly higher runtime and having to inherit from that interface (it will, however, allow new objects to be passed to the function at any time, so long as they implement the interface).