Making a vector of linked lists? - c++

How can I make a vector of linked lists?
For example I have a struct of properties (for the linked-list) defined as follows:
typedef struct property {
string info;
property* implication;
} property;
And then I have a class object:
class objects {
private:
vector<property> *traits;
public:
void giveProperty(property *x) {
traits.push_back(&x);
}
};
Where what I want to do conceptually is give an object certain properties, and each property has a series of implications (which is the linked list) which I can use later. But I am getting the error:
request for member 'push_back' in '((objects*)this)->objects::traits', which is of non-class type 'std::vector >*'
I am having trouble getting this to work. Sorry if this is unclear, if you have questions I will try clarifying myself.

in class objects, you have declared a pointer to a vector of properties, when really you want a vector of property pointers:
class objects {
private:
vector<property*> traits; // Note where * is
public:
void giveProperty(property *x) {
traits.push_back(x); // Note that x is already a pointer, no need to take its address
}
};

I'm not sure why you are using raw pointers. You say you want to have a linked list, but you don't implement that anywhere. Why not use the std::list container for your linked lists and lose the pointers altogether?
#include <string>
#include <vector>
#include <list>
using std::string;
using std::vector;
using std::list;
struct implication {
implication(string name) : name(name) {}
string name;
};
struct property {
property(string info) : info(info) {}
string info;
list<implication> implList;
};
class object {
private:
vector<property> traits;
public:
void giveProperty(const property& x) {
traits.push_back(x);
}
};
int f() {
object o;
property p1("p1");
property p2("p2");
implication i("implic");
p1.implList.push_back(i);
p1.implList.push_back(implication("other implic"));
o.giveProperty(p1);
o.giveProperty(property("p3"));
}

Change this
traits.push_back(&x);
to this:
traits->push_back(*x);
Or probably/possibly, you would want to change this:
vector<property> *traits;
to this:
vector<property*> traits;
I would go for the latter one!

Do you understand what pointers are?
vector<property*> *traits;
You're creating a pointer to a vector, not a vector. You would need to create one:
traits = new vector<property*>;
then access it as:
traits->push_back(x);

Change -
vector<property> *traits;
to
vector<property*> traits; // Needs to be the declaration.
Since you are trying to push_back addresses to the vector traits.
void giveProperty(property *x) {
traits.push_back(&x);
^ Error : With the above modifications made, traits can hold
elements of type property*. By doing &x, you are trying to do
push_back pointer's address which in that case vector should
hold elements of type property**. So, just remove the &
symbol before x while push_back because x is already of type
property*
}

Related

Is it possible to define a list of queues where each queue can be of different types?

I am trying to define a class where the main element is a list of queues.
The problem is that each queue can be of different types.
Here is an example of what I would like to get. If we define these queues:
queue1 (type int) = {5,7,3,4,5}
queue2 (type string) = {"Sam","Peter"}
queue3 (type string) = {"January","February","March"}
queue4 (type int) = {10}
Then, I would like to be able to create objects like these:
object1.list_of_queues = {queue1,queue2}
object2.list_of_queues = {queue2,queue3,queue4}
All of them based on the same class.
I am able to create a type "list of queues", but all of them share the same type:
typedef std::queue<std::string> queue_type; //queue of strings
typedef std::list<queue_type> list_type; //list of queues of (only) strings
Is there any solution without using lists to avoid this type mixing? I was thinking about encapsulating the queues into a new defined type. Or creating a list of pointers, where every pointer points to the right queue, but I don't know if this is possible.
Thank you in advance!
Is it possible to define a list of queues where each queue can be of different types?
Not directly.
A std::queue of one element type is a different type from a queue of another element type. std::list is a homogeneous container: All elements have the same type.
What you can do is have a list or queue of a type-erasing wrapper such as std::variant or std::any which can contain objects of a type from correspondingly limited, or unlimited selection.
Based on your comments, I suspect you want to do something like that:
#include <iostream>
#include <string>
#include <list>
#include <memory>
class Shape
{
public:
virtual double area() const = 0;
};
class Circle : public Shape
{
double radius;
public:
Circle(const double r) : radius(r) {}
double area() const {
return 3.1416 * radius * radius;
}
};
class Square : public Shape
{
double side;
public:
Square(const double s) : side(s) {}
double area() const {
return side * side;
}
};
int main()
{
std::list<std::unique_ptr<Shape>> my_list;
my_list.push_back(std::make_unique<Circle>(2.0));
my_list.push_back(std::make_unique<Square>(4.0));
for(const auto& el : my_list)
std::cout << el->area() << std::endl;
}
Where I used polymorphism/inheritance to create an object of type Shape. Then Im using a list of that parent object as pointer, so it possible to create different child elements such as Cirlce or Square.
Yes there are ways to do this. This utilities both runtime and compile time polymorphism. My favorite utilities the following types.
C++ like pseudo-code follows:
#include <typeinfo>
namespace dynamics {
class AnyBase {
virtual const type_info& getTypeInfo();
virtual ~AnyBase()
}
template<typename T>
class DynamicAny : public AnyBase {
type_info typekind;
T val;
template<typename T>
DynamicAny(const T& t) : typekind(typeof(T)), val(t) {}
//... usual move/copy constructors/operators follow
//conversion operators
inline operator T&() {
return val;
}
inline operator const T&() const {
return val;
}
//possibly comparison operators with const T& too...
//virtual call for type information for this type
const type_info& getTypeInfo() {
return typekind;
}
}
}
You could then include any std::unique_ptr<AnyBase> within a vector or queue or any data structure for that matter. But assign it a DynamicAny<T> of the desired type. Then when you get it out of that data structure simply call getTypeInfo() on the AnyBase to determine which DynamicAny<T> to cast it to.
See type_info for more details.
http://www.cplusplus.com/reference/typeinfo/type_info/
You could also use std::any that does a similar thing.
https://en.cppreference.com/w/cpp/utility/any
c++17 only onward.
typedef std::queue<std::unique_ptr<AnyBase>> queue_type; //queue of unique_ptr of DynamicAny<T>
typedef std::list<queue_type> list_type; //list of queues of (only) strings

Holding Template Class Objects in Array

I have to hold different type of datas in one array for my project. I've created a template class for generating objects.
template<class Queue>
class Template {
public:
Queue value;
Template(Queue input) {
value = input;
}
};
But I can't hold them in one array without using abstract class. I've created a void pointer array for this. And I used it liked that;
void *array[21];
array[index] = new Template<int>(number);
array[index] = new Template<string>(text);
Is there any possible solution without abstract classes? I mean, can i hold this template objects in template class' array?
Create a hierarchy and take advantage of dynamic binding:
class Base {
public:
virtual ~Base() {};
// ...
};
template<class Queue>
class Template : public Base {
Queue value;
public:
Template(Queue const &input) :value(input) {}
// ...
};
And use it as:
Base *array[21];
array[index] = new Template<int>(number);
array[index + 1] = new Template<string>(text);
Furthermore, instead of using raw array and raw pointers use STL facilities like std::array smart pointers (e.g., std::shared_ptr<Base> or std::unique_ptr<Base>):
std::array<std::unique_ptr<Base>, 21> arr;
arr[index].reset(new Template<int>(number));
arr[index + 1].reset(new Template<string>(text));
Also prefer to initialize member variables to the constructor's initializer list than to its body.
This is usually a sign that you should rethink your code structure at a higher level so that you don't need this at all.
Otherwise you have four choices that I see (five if you count the "don't do this" above):
Use a uniform type that can hold all your types of data (for example a std::string and parse the numeric information out when needed). This functionality could be wrapped in a class that provides member functions to make this easier.
Use a boost::variant, if you are new to C++ then I don't recommend tackling this sort of thing right away.
Use a base class as explained by 101010. I would add that you may want an enum in the base class that tells you what type of data is stored
Use a boost::any, this is even more difficult to use than a variant, even though it's easier to understand.
Without more information on what it is you are trying to achieve, we can't really provide any better guidance on how to proceed.
I'd do it using variant types. You can roll out your own but prefer using boost::variant :
#include <boost/variant.hpp>
#include <iostream>
#include <string>
using namespace std;
template<class Queue>
class Template
{
public:
Queue value;
Template() = default;
Template(Queue input) {
value = input;
}
};
template<typename T>
std::ostream& operator<<(std::ostream& os, Template<T> const& t)
{
os << t.value;
return os;
}
int main ()
{
using v_t = boost::variant<Template<int>, Template<string>>;
v_t ar[2];
ar[0] = Template<int>(1);
ar[1] = Template<string>("lmfao");
for (auto&& elem : ar) cout << elem << endl;
}
Demo
Note that
v_t is the type of the variant
v_t can have more types among which you can choose to populate the array
the output operator was only overloaded for demonstration
you get extra functionality by boost::visitor

Map of strings and pointers to templated functions

I'm working on a 2D game engine and I continuosly run into template problems. So, for this one, I've got a templated function like this:
template <class T>
T *S2M_CreateObject(int x, int y) {
return new T(x, y);
}
now, I would like the game to load the level data from a file, and that includes loading and instantiating Object-derived classes, so I made an std::map like this:
map <string, Object *(*)(int x, int y)> o {
{ "warp", &S2M_CreateObject<Warp> }
};
which stores a string that I will be using in the level editor to refer a determined class and maps it to a function pointer that would create an instance of that said class.
I hope you get the idea, this is the approach I like the most but it is not working. However, it works if I delete the Warp template specifier (Warp is a derived class of Object), but that is not the goal. I know I could create a function for every object type I have defined in the game, but since I'm programming a game engine, I can't figure out how many Object-derived classes the user will create and I cannot expect him/her to program each function.
Any other way I can do this?
Whereas Warp* can be implicitly converted to Object*, a pointer to a function returning Warp* cannot be implicitly converted to a pointer to a function returning Object*. Nor, in general, can such a conversion be performed safely at all.
Now the reason why your code doesn't work should be clear. &S2M_CreateObject<Warp> has type Warp* (*)(int, int), and this can't be implicitly converted to Object* (*)(int, int). Instead, you can make the S2M_CreateObject function always return Object* regardless of which type is actually created:
#include <map>
#include <string>
using namespace std;
struct Object {
Object() {}
Object(int x, int y) {}
};
struct Warp : Object {
Warp() {}
Warp(int x, int y) {}
};
template <class T>
Object* S2M_CreateObject(int x, int y) {
return new T(x, y);
}
int main() {
map<string, Object *(*)(int x, int y)> o {
{ "warp", &S2M_CreateObject<Warp> }
};
}
Thanks to your previous help, I could do something like this: here is somehow the working result (simplified). I used it with a quite simple range function
//Define your template function
template<typename Type>
void fnRangeValue(CMyClass * poMyObject, std::string strFormat){
Type tMyField, tMinValue, tMaxValue;
/*Do what you have to here!*/
}
//Define a macro for your pointerFunction
typedef void (*fnPointerFunctionRange)(CMyClass * poMyObject, std::string strFormat );
// Define your lookup table (map)
const std::map<std::string, fnPointerFunctionRange> ST_FORMAT_RANGE_POINTER= {
{"UINT8",&fnRangeValue<uint8_t>},
{"STR1UINT8",&fnRangeValue<uint8_t>},
{"UINT16",&fnRangeValue<uint16_t>},
{"STR2UINT16",&fnRangeValue<uint16_t>},
{"STR4UINT16",&fnRangeValue<uint16_t>},
{"UINT32",&fnRangeValue<uint32_t>},
{"INT8",&fnRangeValue<int8_t>},
{"INT16",&fnRangeValue<int16_t>},
{"STR3INT16",&fnRangeValue<int16_t>},
{"INT32",&fnRangeValue<int32_t>},
{"FLT32",&fnRangeValue<float>},
{"FLT64",&fnRangeValue<double>},
{"STR7FL64",&fnRangeValue<double>},
{"STR8FL64",&fnRangeValue<double>},
};
void fnRangeField(CMyClass * poMyObject){
std::string strFormat;
fnPointerFunctionRange poFonctionRange;
strFormat = "UINT8";
auto itMapRangePointer = ST_EOIIM_FORMAT_RANGE_POINTER.find(strFormat);
if(itMapRangePointer != ST_FORMAT_RANGE_POINTER.end()){
poFonctionRange = ST_FORMAT_RANGE_POINTER.at(strFormat);
// Call of the right template function thanks to pointers
poFonctionRange(poMyObject,strFormat);
}
}
Hope it will help you!

How bad is to use void pointer in std::vector declaration?

I have two different classes as below:
class text
{ };
class element
{ };
And I want to store them in the class node:
template <typename T>
class node
{
T cargo;
std::vector<void*> children;
node(T cargo) : cargo(cargo)
{ };
void add_child(T node)
{
this->children.push_back((void*) node);
}
}
So I would call the node this way storing both, text and element's:
element div;
text msg;
node<element> wrapper(div);
wrapper.add_child(msg);
EDIT: To get back the content I use T typedef type; and convert void pointer to (type*).
I know that's not very elegant nor functional, but I just can't figure out what's the correct way of doing that. So please tell me if this is practically acceptable and if it is not, how to do that in the proper manner.
Thanks in advance!
#include <vector>
using namespace std;
class Element {};
class Text {};
class Nothing {};
class Node
{
private:
vector< Node* > children_;
protected:
Node() {}
public:
void add( Node* p ) { children_.push_back( p ); }
virtual ~Node() {}
};
template< class Cargo >
class CargoNode
: public Node
{
private:
Cargo cargo_;
public:
CargoNode(): cargo_() {}
};
typedef CargoNode< Element > ElementNode;
typedef CargoNode< Text > TextNode;
typedef CargoNode< Nothing > RootNode;
int main()
{
RootNode* root = new RootNode;
root->add( new ElementNode );
root->add( new ElementNode );
root->add( new TextNode );
root->add( new ElementNode );
// Etc.
}
Cheers & hth.,
PS: Error checking, lifetime management, iteration etc. omitted in this example code.
I would say that void* is nearly always "bad" (for some definition of bad). Certainly, there are likely to be better ways of expressing what it is you're trying to do. If it were me writing this code and I knew the types of the values I was going to put in, then I would consider using a Boost.Variant. If I didn't (for example, this was supplied as a library to someone else to "fill up"), then I would use Boost.Any
For example:
template <class T, class U>
struct node
{
typedef boost::variant<T, U> child_type;
std::vector<child_type> children;
void add_child(T const &t)
{
children.push_back(t);
}
void add_child(U const &u)
{
children.push_back(u);
}
};
...
node<text, element> n;
n.add_child(text("foo"));
A non-boost typed union solution:
struct node
{
struct child
{
int type; // 0 = text; 1 = element
union
{
text* t;
element* e;
} u;
};
std::vector<child> children;
void add_child(text* t)
{
child ch;
ch.type = 0;
ch.u.t = t;
children.push_back(ch);
}
void add_child(element* e)
{
child ch;
ch.type = 1;
ch.u.e = t;
children.push_back(ch);
}
};
Note: you have to be a whole lot more careful about memory management with the typed union.
Define a shared base class for element and text and then add_child can take a pointer to the base class, and the vector can store pointers to the base class.
How would you get them back if you do this? From a void* there is no way to determine what is actually stored on the address.
Edit:
If you always do a cast into T* then you can simply take T* as the parameter.
If your container value is limited to a small number of types, you could achieve this using boost::variant as shown here:
#include <vector>
#include <boost/variant.hpp>
using namespace std;
class text
{ };
class element
{ };
template <typename T>
class node
{
T cargo;
static std::vector<boost::variant<text, element>> children;
node(const T& cargo) : cargo(cargo)
{ };
void add_child(const T& node)
{
children.push_back(boost::variant<text, element>(node));
}
};
I have taken the liberty of suggesting a couple of other mods - use const reference instead of pass-by-value on node constructor and add_child; make the container children static as I don't think it makes sense for each node<T> to have its own container. Locking would be required for multithreaded usage of add_child in this case. These comments apply whether you can use Boost or not in your final solution.
You can perform operations on the vector elements using either get or static_visitor - the latter is preferable since you can make this generic - as shown here. An example of vector iteration analogous to what you would use for this solution:
class times_two_generic
: public boost::static_visitor<>
{
public:
template <typename T>
void operator()( T & operand ) const
{
operand += operand;
cout << operand << endl;
}
};
std::vector< boost::variant<int, std::string> > vec;
vec.push_back( 21 );
vec.push_back( "hello " );
times_two_generic visitor;
std::for_each(
vec.begin(), vec.end()
, boost::apply_visitor(visitor)
);
Output is:
42
hello hello
First, there's no such a thing as "bad" to use a void pointer. Forget all the conventions and bla-blas, and do what's most appropriate for your case.
Now, in you specific case, if there's any connection between those two classes - you may declare a base class, so that those two will inherit it. Then, you may declare the vector of a pointer of that base class.

What is the simplest way to create and call dynamically a class method in C++?

I want to fill a map with class name and method, a unique identifier and a pointer to the method.
typedef std::map<std::string, std::string, std::string, int> actions_type;
typedef actions_type::iterator actions_iterator;
actions_type actions;
actions.insert(make_pair(class_name, attribute_name, identifier, method_pointer));
//after which I want call the appropriate method in the loop
while (the_app_is_running)
{
std::string requested_class = get_requested_class();
std::string requested_method = get_requested_method();
//determine class
for(actions_iterator ita = actions.begin(); ita != actions.end(); ++ita)
{
if (ita->first == requested_class && ita->second == requested_method)
{
//class and method match
//create a new class instance
//call method
}
}
}
If the method is static then a simple pointer is enough and the problem is simple,
but I want to dynamically create the object so I need to store a pointer to class and an offset for the method and I don't know if this works (if the offset is always the same etc).
The problem is that C++ lacks reflection, the equivalent code in a interpreted language with reflection should look like this (example in PHP):
$actions = array
(
"first_identifier" => array("Class1","method1"),
"second_identifier" => array("Class2","method2"),
"third_identifier" => array("Class3","method3")
);
while ($the_app_is_running)
{
$id = get_identifier();
foreach($actions as $identifier => $action)
{
if ($id == $identifier)
{
$className = $action[0];
$methodName = $action[1];
$object = new $className() ;
$method = new ReflectionMethod($className , $methodName);
$method -> invoke($object);
}
}
}
PS: Yes I'm trying to make a (web) MVC front controller in C++.
I know I know why don't use PHP, Ruby, Python (insert your favorite web language here) etc?, I just want C++.
Perhaps you're looking for member function pointers.
Basic usage:
class MyClass
{
public:
void function();
};
void (MyClass:*function_ptr)() = MyClass::function;
MyClass instance;
instance.*function_ptr;
As stated in the C++ FAQ Lite, macros and typedefs would greatly increase readability when using member function pointers (because their syntax isn't common in code).
I wrote that stuff last hours, and added it to my collection of useful stuff. The most difficult thing is to cope with the factory function, if the types you want to create are not related in any way. I used a boost::variant for this. You have to give it a set of types you ever want to use. Then it will keep track what is the current "active" type in the variant. (boost::variant is a so-called discriminated union). The second problem is how you store your function pointers. The problem is that a pointer to a member of A can't be stored to a pointer to a member of B. Those types are incompatible. To solve this, i store the function pointers in an object that overloads its operator() and takes a boost::variant:
return_type operator()(variant<possible types...>)
Of course, all your types' functions have to have the same return type. Otherwise the whole game would only make little sense. Now the code:
#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/preprocessor/repetition.hpp>
#include <map>
#include <string>
#include <iostream>
// three totally unrelated classes
//
struct foo {
std::string one() {
return "I ";
}
};
struct bar {
std::string two() {
return "am ";
}
};
struct baz {
std::string three() const {
return "happy!";
}
};
// The following are the parameters you have to set
//
// return type
typedef std::string return_type;
// variant storing an object. It contains the list of possible types you
// can store.
typedef boost::variant< foo, bar, baz > variant_type;
// type used to call a function on the object currently active in
// the given variant
typedef boost::function<return_type (variant_type&)> variant_call_type;
// returned variant will know what type is stored. C++ got no reflection,
// so we have to have a function that returns the correct type based on
// compile time knowledge (here it's the template parameter)
template<typename Class>
variant_type factory() {
return Class();
}
namespace detail {
namespace fn = boost::function_types;
namespace mpl = boost::mpl;
// transforms T to a boost::bind
template<typename T>
struct build_caller {
// type of this pointer, pointer removed, possibly cv qualified.
typedef typename mpl::at_c<
fn::parameter_types< T, mpl::identity<mpl::_> >,
0>::type actual_type;
// type of boost::get we use
typedef actual_type& (*get_type)(variant_type&);
// prints _2 if n is 0
#define PLACEHOLDER_print(z, n, unused) BOOST_PP_CAT(_, BOOST_PP_ADD(n, 2))
#define GET_print(z, n, unused) \
template<typename U> \
static variant_call_type get( \
typename boost::enable_if_c<fn::function_arity<U>::value == \
BOOST_PP_INC(n), U>::type t \
) { \
/* (boost::get<actual_type>(some_variant).*t)(n1,...,nN) */ \
return boost::bind( \
t, boost::bind( \
(get_type)&boost::get<actual_type>, \
_1) BOOST_PP_ENUM_TRAILING(n, PLACEHOLDER_print, ~) \
); \
}
// generate functions for up to 8 parameters
BOOST_PP_REPEAT(9, GET_print, ~)
#undef GET_print
#undef PLACEHOLDER_print
};
}
// incoming type T is a member function type. we return a boost::bind object that
// will call boost::get on the variant passed and calls the member function
template<typename T>
variant_call_type make_caller(T t) {
return detail::build_caller<T>::template get<T>(t);
}
// actions stuff. maps an id to a class and method.
typedef std::map<std::string,
std::pair< std::string, std::string >
> actions_type;
// this map maps (class, method) => (factory, function pointer)
typedef variant_type (*factory_function)();
typedef std::map< std::pair<std::string, std::string>,
std::pair<factory_function, variant_call_type>
> class_method_map_type;
// this will be our test function. it's supplied with the actions map,
// and the factory map
std::string test(std::string const& id,
actions_type& actions, class_method_map_type& factory) {
// pair containing the class and method name to call
std::pair<std::string, std::string> const& class_method =
actions[id];
// real code should take the maps by const parameter and use
// the find function of std::map to lookup the values, and store
// results of factory lookups. we try to be as short as possible.
variant_type v(factory[class_method].first());
// execute the function associated, giving it the object created
return factory[class_method].second(v);
}
int main() {
// possible actions
actions_type actions;
actions["first"] = std::make_pair("foo", "one");
actions["second"] = std::make_pair("bar", "two");
actions["third"] = std::make_pair("baz", "three");
// connect the strings to the actual entities. This is the actual
// heart of everything.
class_method_map_type factory_map;
factory_map[actions["first"]] =
std::make_pair(&factory<foo>, make_caller(&foo::one));
factory_map[actions["second"]] =
std::make_pair(&factory<bar>, make_caller(&bar::two));
factory_map[actions["third"]] =
std::make_pair(&factory<baz>, make_caller(&baz::three));
// outputs "I am happy!"
std::cout << test("first", actions, factory_map)
<< test("second", actions, factory_map)
<< test("third", actions, factory_map) << std::endl;
}
It uses pretty fun techniques from boost preprocessor, function types and bind library. Might loop complicated, but if you get the keys in that code, it's not much to grasp anymore. If you want to change the parameter count, you just have to tweak variant_call_type:
typedef boost::function<return_type (variant_type&, int)> variant_call_type;
Now you can call member functions that take an int. Here is how the call side would look:
return factory[class_method].second(v, 42);
Have fun!
If you now say the above is too complicated, i have to agree with you. It is complicated because C++ is not really made for such dynamic use. If you can have your methods grouped and implemented in each object you want create, you can use pure virtual functions. Alternatively, you could throw some exception (like std::runtime_error) in the default implementation, so derived classes do not need to implement everything:
struct my_object {
typedef std::string return_type;
virtual ~my_object() { }
virtual std::string one() { not_implemented(); }
virtual std::string two() { not_implemented(); }
private:
void not_implemented() { throw std::runtime_error("not implemented"); }
};
For creating objects, a usual factory will do
struct object_factory {
boost::shared_ptr<my_object> create_instance(std::string const& name) {
// ...
}
};
The map could be composed by a map mapping IDs to a pair of class and function name (the same like above), and a map mapping that to a boost::function:
typedef boost::function<my_object::return_type(my_object&)> function_type;
typedef std::map< std::pair<std::string, std::string>, function_type>
class_method_map_type;
class_method_map[actions["first"]] = &my_object::one;
class_method_map[actions["second"]] = &my_object::two;
Calling the function would work like this:
boost::shared_ptr<my_object> p(get_factory().
create_instance(actions["first"].first));
std::cout << class_method_map[actions["first"]](*p);
Of course, with this approach, you loose flexibility and (possibly, haven't profiled) efficiency, but you greatly simplify your design.
I think the most important thing to find out here is, do all of your methods have the same signature? If they do, this is a trivial use of boost bind(if you're into that), functors are an option(the static, duck type kind), or just plain ole virtual inheritance is an option. Inheritance isnt currently in vogue but its pretty easy to understand and I dont think it complicates things anymore then using boost bind(imho best for small non systemic functors).
here is a sample implementation
#include<iostream>
#include<map>
#include<string>
using std::map;
using std::string;
using std::cout;
using std::pair;
class MVCHandler
{
public:
virtual void operator()(const string& somekindofrequestinfo) = 0;
};
class MyMVCHandler : public MVCHandler
{
public:
virtual void operator()(const string& somekindofrequestinfo)
{
cout<<somekindofrequestinfo;
}
};
void main()
{
MyMVCHandler myhandler;
map<string, MVCHandler*> handlerMap;
handlerMap.insert(pair<string, MVCHandler*>("mysuperhandler", &myhandler));
(*handlerMap["mysuperhandler"])("somekindofrequestdata");
}
Like many C++ questions, this looks like another application of Boost. You basically want to store the result of boost::bind(&Class::member, &Object). [edit] Storing such a result is easy with boost::function.
You can try using factory or abstract factory design patterns for the class, and a function pointer for the function.
I found the following 2 web pages with implementations when I was searching for solutions for a similar problem:
Factory
Abstract factory
If you do not want to use member function pointers, you can use statics which take an argument of the class instance. For example:
class MyClass
{
public:
void function();
static void call_function(MyClass *instance); // Or you can use a reference here.
};
MyClass instance;
MyClass::call_function(&instance);
This requires more work on the coder and causes maintainability issues (since if you update the signature of one, you must update that of the other as well).
You could also use a single static function which calls all your member functions:
class MyClass
{
public:
enum Method
{
fp_function,
};
void function();
static void invoke_method(MyClass *instance, Method method); // Or you can use a reference here.
};
void MyClass::invoke_method(MyClass *instance, Method method)
{
switch(method)
{
default:
// Error or something here.
return;
case fp_function:
instance->function();
break;
// Or, if you have a lot of methods:
#define METHOD_CASE(x) case fp_##x: instance->x(); break;
METHOD_CASE(function);
#undef METHOD_CASE
}
// Free logging! =D
}
MyClass instance;
MyClass::invoke_method(instance, MyClass::fp_function);
You can also use dynamic loading of the functions:
Use GetProcAddress in Windows, and dlsym in Unix.
Go for Subject-Observer design pattern.