Map of strings and pointers to templated functions - c++

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!

Related

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);
}

Proxy to an object, proper const qualification and lack thereof

I just found something that looks like a quirk to me. Consider :
struct Tile {
Tile(Map &map, int, int)
: map(map) { }
void destroy();
void display() const;
Map &map;
};
This (stripped down) class is an accessor object. It's constructed by the Map itself as such :
Tile Map::operator ()(int x, int y) {
return Tile(*this, x, y);
}
Tile const Map::operator ()(int x, int y) const {
return Tile(*this, x, y);
}
So a Map can return a Tile from which we can call destroy() (which updates the map), and a Map const can only return a Tile const, from which we can only call the non-modifying display() method.
So everything's good, right ? Well, not quite. Because even though it seemed pretty straightforward at first, I can't figure out how to construct a Tile from a Map const, because of the Map& constructor parameter.
I also tried removing Tile's constructor and aggregate-initializing it, to no avail :
Tile const Map::operator ()(int x, int y) const {
return { *this, x, y };
}
... which looks even stranger to me, since I get an...
error: invalid initialization of reference of type ‘Map&’ from expression of type ‘const Map’
... even though a Tile const should only contain const fields, shouldn't it ?
Why does the compiler complain on that last one (the first is quite logical), and can I do something short of rewriting the whole Tile class specifically for const access ? Could it be one of the mythical places where const_cast is right ?
Thanks in advance.
Daniel's on the right track - you definitely need a Tile and ConstTile class, which can be templated for simplicity, but you need to deal with when you can call destroy() and how you can construct them. To that end:
template<class MapT>
struct TileT {
TileT(MapT &map, int, int)
: map(map) { }
// we want to be able to construct ConstTile from Tile
template <typename M>
TileT(const TileT<M>& tile)
: map(tile.map) { }
void destroy() {
static_assert(!std::is_const<MapT>::value, "Cannot call destory() from ConstTile");
// rest of implementation
}
void display() const;
MapT &map;
};
using Tile = TileT<Map>;
using ConstTile = TileT<const Map>;
That will give you the desired functionality and will work in a similar fashion to how iterator/const_iterator work. So you can do stuff like:
Map map;
...
ConstTile tile = map(4,3); // non-const map, ConstTile is ok
I see no way around creating two versions of the Tile class: One for const access and one for mutable access. Consider the following: What should the destroy function do, if the Map reference is const?
If you want to get around making a Tile and a ConstTile version of the class, you can use templates to achieve the same effect and still avoid code duplication.
template<class MapT>
struct Tile {
Tile(MapT &map, int, int)
: map(map) { }
template<typename U = MapT>
std::enable_if<std::is_const<U>::value> destroy();
void display() const;
MapT &map;
};
MapT can now be Map or const Map depending on the instantiation.

variadic templates: invalid use of void expression

I'm trying to create a generic collection for events so that it'll be reusable for different kind of event-sets. While playing around with variadic templates, I came across THIS answer, which helped me for my example here:
#include <boost/test/unit_test.hpp>
#include <string>
#include <unordered_map>
namespace
{
struct Event3 {
static const int event_type = 3;
int a;
};
struct Event5 {
static const int event_type = 5;
double d;
};
struct Event7 {
static const int event_type = 7;
std::string s;
};
template <class ...K>
void gun(K...) {}
template <class... Ts>
class EventCollection
{
template <typename T>
void update_map(std::unordered_map<int, size_t> & map, const T &)
{
BOOST_CHECK(map.find(T::event_type) == map.end());
map[T::event_type] = sizeof(T);
}
public:
std::unordered_map<int, size_t> curr_map;
EventCollection(Ts... ts)
{
gun(update_map(curr_map, ts)...); // will expand for each input type
}
};
} // namespace
BOOST_AUTO_TEST_CASE( test_01 )
{
Event3 x{13};
Event5 y{17.0};
Event7 z{"23"};
EventCollection<Event3, Event5, Event7> hoshi(x, y, z);
BOOST_CHECK_EQUAL(hoshi.curr_map.size(), 3);
}
However, the line
gun(update_map(curr_map, ts)...); // will expand for each input type
gives me an 'error: invalid use of void expression'.
Can anybody tell me, how to solve this?
The problem is that your update_map returns void. Hence you cannot write this:
gun(update_map(curr_map, ts)...);
because the return values of update_map is supposed to be passed to gun as arguments.
The fix is to pass something to gun as argument, so you can do this:
gun( (update_map(curr_map, ts),0)...);
Now the expresssion (update_map(curr_map, ts),0) turns out to be 0 which is passed as argument to gun. That should work. You can think of this as:
T argmument = (update_map(curr_map, ts),0); //argument is 0, and T is int
--
Also, as the other answer pointed out that the order of evaluation of arguments to gun() are unspecified (means the order in which the function update_map is called, is unspecified) which may lead to undesired result. The other solution has given a solution to this problem. Here is another one (which is a bit tricky and easy!):
//ensure that the size of the below array is at least one.
int do_in_order[] = {0, (update_map(curr_map, ts),0)...};
Because the order of initialization of array elements are well-defined (from left-to-right), now all the calls to update_map happens in well-defined order.
update_map is a function that returns void.
That line consists of calling update_map, and then passing the return value to gun.
You cannot pass a void return value to another function.
Hence "invalid use of void expression".
There are many ways to fix this, including having update_map return struct empty {};
Note that your code results in the calls of update_map happening in an unspecified order. This can easily lead to unexpected behavior.
Might I suggest:
void do_in_order();
template<typename F0, typename... Functors>
void do_in_order( F0&& f0, Functors&& funcs... ) {
f0();
do_in_order( std::forward<Functors>(funcs)... );
}
then replace the call to gun with:
do_in_order([&]{update_map(curr_map, ts);}...); // will expand for each input type
which packages up the things to do into lambdas, which are then called in order that they are passed.
Now, this also does away with the need for an update_map function entirely:
do_in_order([&]{
BOOST_CHECK(curr_map.find(ts::event_type) == curr_map.end());
map[ts::event_type] = sizeof(ts);
}...);
which is awesome.

Universal function pointer

There is some class which have methods like:
int getSomething1();
std::string getSomething2();
someClass getSomething3();
There is structure which describes fields of this class like:
{"name of field", pointer to getter, std::type_info}
Then I would like to use it as follows:
if(type == int){
field_int = (int)getter();
}
else if(type == std::string){
field_string = (std::string)getter();
}
etc.
How to transform getters like
int getSomething1();
std::string getSomething2();
etc.
to some universal function pointer and then to get the correct value of field?
This answer of mine to another question addresses your problem pretty well. With some minor modifications, you get this:
template<class C, class T>
T get_attribute(const C& instance, T (C::*func)() const) {
return (instance.*func)();
}
Assuming the following:
struct Foo {
int getSomething1() const;
std::string getSomething2() const;
someClass getSomething3() const;
};
You can use it like this:
Foo foo;
int value = get_attribute<Foo, int>(foo, &Foo::getSomething1);
std::string value = get_attribute<Foo, std::string>(foo, &Foo::getSomething2);
someClass value = get_attribute<Foo, someClass>(foo, &Foo::getSomething3);
You can of course transform get_attribute to a functor to bind some or all of the arguments.
There is no formal universal function pointer, the equivalent of void*
for data. The usual solution is to use void (*)(); you are guaranteed
that you can convert any (non-member) function pointer to this (or any
other function pointer type) and back without loss of information.
If there is a certain similarity in the function signatures (e.g. all
are getters, with no arguments) and how they are used, it may be
possible to handle this with an abstract base class and a set of derived
classes (possibly templated); putting pointers to instances of these
classes in a map would definitely be more elegant than an enormous
switch.
What you are trying to achieve can be better achieved with already existing containers such as a boost fusion sequence. I'd advice that you try this first.
Templates to the rescue!
// Create mapping of type to specific function
template <typename T> T getSomething(); // No default implementation
template <> int getSomething<int>() { return getSomething1(); }
template <> std::string getSomething<std::string>() { return getSomething2(); }
template <> someClass getSomething<someClass>() { return getSomething3(); }
// Convenience wrapper
template <typename T> void getSomething(T& t) { t = getSomething<T>(); }
// Use
int i = getSomething<int>();
std::string s;
getSomething(s);
As I understand, your difficulty is in storing the function pointers, since they are of different types. You can solve this using Boost.Any and Boost.Function.
#include <boost/any.hpp>
#include <boost/function.hpp>
int getInt() {
return 0;
}
std::string getString() {
return "hello";
}
int main()
{
boost::function<boost::any ()> intFunc(getInt);
boost::function<boost::any ()> strFunc(getString);
int i = boost::any_cast<int>(intFunc());
std::string str = boost::any_cast<std::string>(strFunc());
}

passing functions

Ok, it's been a while since I wrote in C++.
and I've never done anything quiet this high level.
So basically I need to create a class.
The constructor for the class needs to take a reference (or pointer) to a method form another class, or to a function.
Basically I have a class that needs to on occasion read a value from a fltk valuator (version 1.1.x), and then change some stuff about itself.
Each object will have it's own valuator associated with it.
(they also have a link to another object of the same parent, which after updating them selves from the valuator will tell to update, and so on)
So how do i pass functions around, in constructors?
Here is an example where a method of Foo is passed to the Bar constructor and later invoked on a given Bar object:
struct Foo
{
int z;
int add(int x, int y)
{
return x + y + z;
}
int mul(int x, int y)
{
return x * y * z;
}
};
typedef int (Foo::*foo_method)(int, int);
struct Bar
{
foo_method m;
Bar(foo_method m) : m(m) {}
int call_on(Foo* foo)
{
return (foo->*m)(4, 2);
}
};
int main()
{
Bar bar(&Foo::add);
Foo foo = { 123 };
bar.call_on(&foo);
}
If, on the other hand, you already know the Foo object at Bar construction time, then Bar does not really care which class the method belongs to. All it needs is a functor to call later, and the Foo object can simply be bound by the client.
#include <functional>
struct Bar
{
std::function<int (int, int)> f;
Bar(std::function<int (int, int)> f) : f(f) {}
int call()
{
return f(4, 2);
}
};
using namespace std::placeholders;
int main()
{
Foo foo = { 123 };
Bar bar(std::bind(&Foo::add, &foo, _1, _2));
bar.call();
}
If you don't have a C++0x compiler, replace std::bind with std::tr1::bind or boost::bind.
Your constructor might look something like this:
// convenient typedef. This is for a pointer to a function in Foo
// The function returns void and takes no parameters.
typedef void (Foo::*FooPtr)();
class Bar {
public:
Bar (FooPtr foo_ptr);
};
Check out some web references for more details on the syntax for pointer-to-members. It's a lot easier if you get familiar with it first.
As an additional note, check out the functions mem_fun and mem_fun_ref. These may do what you need.
The easiest way to capture this is with boost::function. It can store function pointers, but also the result of binding a member function to an object.
For instance,
class Foo {
Foo(boost::function<int(void)>);
};
will allow you to accept any source of integers.