Related
I have the following code:
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
struct foo { static void visual_plot() { x.draw(); } }; // Error.
app.add_visual_scene(Scene("Visual Plot", foo::visual_plot));
app.run();
return 0;
}
And I get the following error:
||=== Build: Debug in Joy-Plus-Plus (compiler: GNU GCC Compiler) ===|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|54|error: use of local variable with automatic storage from containing function|
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|53|error: 'Image x' declared here|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
I'm writing a multimedia/game engine for the Allegro 5 library, and I've abstracted the drawing part of the main-loop (As well as the event parts) into "scene" objects with plots (Functions). Each procedure is passed to the App, so that it gets "run" inside the main-loop. The problem is, the "C++ approach" does not work:
Image x("sample.png");
void visual_plot()
{
x.draw(); // Problem.
}
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
app.add_visual_scene(Scene("Visual Plot", visual_plot));
app.run();
return 0;
}
Although the code runs, this happens:
And if I put the x inside the visual_plot, the image is loaded normally:
But now I have a huge performance problem, since a new Image object is being created at each main-loop (And it's not long until the whole thing freezes).
The image is not found when I put it outside the scope of the function because it must come after the initialization of the App, but since I have a typedef function pointer in Scene that takes that function as an argument, I also must give it a void function. The problem is that I can't create local / nested functions in C++ (After the initialization of the App). So, in order to avoid the problem, I've tried the obvious (Lambda expression / closure):
int main(int argc, char **argv)
{
App app(800, 600);
app.add_event_scene(Scene("Event Plot", event_plot));
Image x("sample.png");
app.add_visual_scene(Scene("Visual Plot", [&x]()->void{x.draw();}));
app.run();
return 0;
}
The problem is that the second argument of the constructor of Scene takes a function pointer:
typedef void(*plot)();
typedef map<string, plot> act;
class Scene
{
private:
string name;
plot p;
public:
Scene(string name, plot p);
~Scene() {};
string get_name();
plot get_plot();
void set_name(string value);
void set_plot(plot value);
};
And since functions cannot be passed as parameters, and get decayed to pointers, the same also applies to the lambda expression (Which is not a function), so I get the following error:
G:\Development\Game-Development\CB\Joy-Plus-Plus\main.cpp|52|error: no matching function for call to 'Scene::Scene(const char [12], main(int, char**)::__lambda0)'|
Facing such a tragedy, how can I simulate a nested function in C++11? Since simulating like this answer does not work.
OBS: I agree that it could be a design problem, but I pretty much don't see it that way. For me, C++ just don't want me to pass that bloody function as a parameter by any means (So, I ask for the help of you long C++ Wizards).
Simply put the image inside the visual_plot function and make it static:
void visual_plot()
{
static Image img("sample.png");
x.draw(); // Problem.
}
This will initialize img the first time visual_plot is called, and only then. This will solve both the performance problem and the "it must be initialized after app.run()" issue.
It is a design problem. In order to accomplish what you are trying to do you need two pieces of information: the code to execute and the data to execute it against.
A lambda isn't magic, it simply encapsulates both of these into an object, that's why it doesn't decay nicely to a single function pointer. A lambda with captures is syntactic sugar for a function object:
int x, y;
float f;
// ...
auto l = [x, &y, f] () { return static_cast<int>((x + y) * f); };
int r = l();
is saving you from writing
struct Values {
int x;
int& y;
float f;
int operator() () {
return static_cast<int>((x + y) * f);
}
Capture(int x_, int& y_, float f_) : x(x_), y(y_), f(f_) {}
};
//...
Capture c(x, y, f);
int r = c();
That's a member function call at the end there, so two pointers are involved: a pointer to the member function 'operator()' and a pointer to the instance to call it on.
int r = Capture::operator=(&c); // pseudo
Using a static or global variable you could make the address of the data known at compile time and so allow yourself to only need a function pointer.
But your design is that of a strcpy that only takes one argument or a print function that takes none: how do you know what to copy or print?
Better designs would be either to let you pass a function object to the plot functions, see how STL predicates work, which would allow both function pointers and lambdas, or use virtual functions and subclassing.
struct Scene { virtual void plot(); };
struct MyScene : public Scene {
Image x;
MyScene() : x("image") {}
void plot() override { x.draw(); }
};
The pitfall of this approach is "slicing", you need to pass Scene by reference rather than by value if you are allowing derived types:
void foo(Scene& s) {
s.plot();
}
foo(MyScene(...)); // not going to go well
I'm trying to avoid using global variables in an openCV project (I'll have my supervisor no doubt teach me as to why they are bad rah rah rah :) - but at the moment they seem to be the only way I can get information out of mouse and trackbar callback functions.
Using the mouse example - at the moment I have as globals:
vector<Point2d> vectorOfPoints;
int clickCount = 0;
At the moment I have this line in main:
setMouseCallback("test",onMouse, NULL);
Then above main:
void onMouse(int event, int x, int y, int f, void* ){
if(event == CV_EVENT_LBUTTONDOWN){
vectorOfPoints.push_back(Point(x,y));
clickCount++;
}
}
It is working, but what is the syntax to get read/write access to both vectorOfPoints and clickCount inside the callback function without using globals?
I have found this question online a few times but the answers are unclear to me or wont work. There are hints within comments as how to do it, but I am so far unable to interpret the jargon correctly.
I was hoping for something as simple as the syntax I use to pass variables as references to methods ...
void referenceExampleMethod(vector<Point2d>& referenceExample){
//do something with referenceExample...
}
...less convoluted the better
I'm scared to ask (jargon overload!) but maybe it's 100% relevant - what is void* ??
Any help appreciated
I agree with the first part of the #jschultz410's answer about the pointer to some place in memory. However, I disagree with using raw pointers in the wild.
You should define your own data type, holding all your data, it could be struct or class, or std::pair, or std::tuple, whatever, the choice is yours.
Then you create an object of that type and use its address in the last argument for setMouseCallback.
The main thing you must ensure - the life time of that object must cover the life time of the window. That is, the object must be created before the first call to onMouse and destroyed after the last one. You could do this by declaring the variable in the beginning of your main. Then the object will be created early after the program start and destroyed near its finish automatically by the compiler. Here is the example.
typedef std::pair<vector<Point2d>, int> data_holder_type; // note the absence of references, this pair holds std::vector and int
void onMouse(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type *dholder = static_cast<data_holder_type *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
....
int main(void) {
data_holder_type dholder;
// add code to initialize your dholder;
...
setMouseCallback("test", onMouse, &dholder);
...
cv::waitKey(); // wait until the window is closed
// read values from dholder and process them
} //dhloder is deleted somewhere here
Another important thing is the concurrent access to this object. onMouse is called from the separate parallel thread, and if your dholder is read or modified both in main, and onMouse simultaneously while the window is open, race conditions will occur. In general, they usually cause unpredictable and very hard to catch bugs.
Everything is fine while your main doesn't access dholder until the window is closed.
As for your question about void *. Note the lines inside if in onMouse. ptr points to the object of type void. That object has no any members, first, or second, or any others. You'll get the compiler error if you'll try to access them using ptr (e.g. ptr->first). Therefore you have to cast this pointer to pointer to another type, that contains some info about the object it points to, data_holder_type * in this case.
Any pointer type can be cast to void *, and void * can be cast to any other pointer type. This allows you to have several different callbacks for different windows.
Beware of wrong casts! No checks is done by compiler.
This example shows how to set 3 different mouse callbacks for windows with different titles.
typedef blah-blah-blah1 data_holder_type1;
typedef blah-blah-blah2 data_holder_type2;
typedef blah-blah-blah3 data_holder_type3;
void onMouse1(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type1 *dholder = static_cast<data_holder_type1 *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
void onMouse2(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type2 *dholder = static_cast<data_holder_type2 *>(ptr);
// processing, related to another data type
}
}
void onMouse3(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type3 *dholder = static_cast<data_holder_type3 *>(ptr);
// process
}
}
int main(void) {
data_holder_type1 dholder1;
data_holder_type2 dholder2;
data_holder_type3 dholder3;
// add code to initialize your dholders;
...
setMouseCallback("test1", onMouse1, &dholder1);
setMouseCallback("test2", onMouse2, &dholder2);
setMouseCallback("test3", onMouse3, &dholder3);
...
}
The last parameter to setMouseCallback is passed back to you when onMouse is called. That is what the void * is in onMouse: the pointer that you passed to setMouseCallback. A void * is a pointer to an unspecified type. You can think of it as a generic pointer to some place in memory.
In your case, you would likely pass the address of a struct that either contains or points to the variables that you want to have access to inside onMouse.
#include <utility>
...
typedef std::pair<std::vector<Point2d>&, int&> my_pair;
...
my_pair *p = new my_pair(vectorOfPoints, clickCount); // TODO: needs to be deallocated eventually
setMouseCallback("test", onMouse, p);
The above assumes that vectorOfPoints and clickCount are already allocated somewhere else (e.g. - dynamically, statically, on the main thread's stack, etc.) and will remain so for the duration of your callbacks. Then,
void onMouse(int event, int x, int y, int f, void *pptr)
{
my_pair *p = (my_pair*) pptr;
if(event == CV_EVENT_LBUTTONDOWN){
p->first.push_back(Point(x,y));
p->second++;
}
}
To not mess around with global variables and functions, I'd like to use a function of a class as a function for a trackbar handle in OpenCV. Following code illustrates the idea:
void cam::set_Trackbarhandler(int i, void *func)
{
/* This function might be called whenever a trackbar position is changed */
}
void cam::create_Trackbars(void)
{
/**
* create trackbars and insert them into main window.
* 3 parameters are:
* the address of the variable that is changing when the trackbar is moved,
* the maximum value the trackbar can move,
* and the function that is called whenever the trackbar is moved
*/
const string trck_name = "Exposure";
char wnd_name[128];
get_Mainwindowname(wnd_name, sizeof(wnd_name));
createTrackbar(trck_name, //Name of the trackbar
wnd_name, //Name of the parent window
&setting, //value that's changed
(int)out_max, //maximum value
this->set_Trackbarhandler); //pointer to the function that's called
}
I hope that outlines it. The error I get when compiling reads
error: cannot convert 'cam::set_Trackbarhandler' from type 'void (cam::)(int, void*)' to type 'cv::TrackbarCallback {aka void (*)(int, void*)}'|
Is there a way to cast void (cam::)(int, void*) into a simple void (*)(int, void*) or do I have to use a global function, that is
void set_Trackbarhandler(int i, void *func)
? If I have to do it like that, my last resort is to use the void pointer (see http://docs.opencv.org/modules/highgui/doc/user_interface.html) and send a pointer to the class back in, as
createTrackbar(trck_name,
wnd_name,
&setting,
(int)out_max,
set_Trackbarhandler, //now a global function
this);
I guess. In the set_Trackbarhandler function I'd make a cast like
cam *ptr = static_cast<cam *>(func);
Sounds a bit complicated, though.
well. you need some indirection, but it's not that bad...
class cam
{
public:
void myhandler(int value)
{
// real work here, can use 'this'
}
static void onTrack(int value, void* ptr)
{
cam* c = (cam*)(ptr);
c->myhandler(value);
}
};
createTrackbar(trck_name,
wnd_name,
&setting,
(int)out_max,
cam::onTrack, //now a static member
this);
I have an application that is creating maps for civilization V. As an interesting design choice I decided to create a couple of functions that would do the looping through the map for me. This way I could pass a function pointer or a lambda function to that function that goes through the whole map doing something to each tile. Reasoning behind this was if I or someone else would change the way the map is stored (from 2D array to a 2D vector or whatever) one would only need to change one function instead of the whole codebase.
Now the problem, here is some code first.
Error code.
case ALL_SNOW:
m.loop_through_limit([] (Tile* t) {
t = new Snow(t->get_x(), t->get_y());
return t;
}, x, y, width, height);
break;
case PTN_ONE:
m.loop_through_limit([&] (Tile* t) {
int cur_x = t->get_x();
int cur_y = t->get_y();
t = new Plains(cur_x, cur_y);
// if (y <= height/4 || y >= (height*3)/4) {
// Top quarter rows and bottom quarter rows
// t = new Ocean(cur_x, cur_y);
// } else if (cur_x <= width/4) {
// Leftmost columns
// t = new Ocean(cur_x, cur_y);
// } else if (cur_x >= (width*3)/4) {
// Rightmost columns
// t = new Desert(cur_x, cur_y);
// }
return t;
}, x, y, width, height);
break;
Definitions from header file.
void loop_through(void (*)(Tile* t));
void loop_through_limit(Tile* (*)(Tile* t), int start_x, int start_y, int width, int height);
Now the difference in each case isn't much apart from the commented out code. This works fine. When I comment out that if statement block, then this is my output.
c++ -c -g -O3 -ffast-math -Wall -Weffc++ -std=c++0x -o tile_block.o tile_block.cpp
tile_block.cpp: In static member function ‘static void TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)’:
tile_block.cpp:82:35: error: no matching function for call to ‘Map::loop_through_limit(TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)::<lambda(Tile*)>, int&, int&, int&, int&)’
tile_block.cpp:82:35: note: candidate is:
map.h:26:10: note: void Map::loop_through_limit(Tile* (*)(Tile*), int, int, int, int)
map.h:26:10: note: no known conversion for argument 1 from ‘TileBlock::write(Map&, TileBlock::Patterns, int, int, int, int)::<lambda(Tile*)>’ to ‘Tile* (*)(Tile*)’
And I believe the problem comes when I start using the parameters I'm trying to capture by reference. Then it starts to turn into a "lambda" function instead of just a "function pointer", maybe I'm just not getting it.
Any suggestions?
C++11 lambda are not function pointers if they capture variables. What you need is called std::function, especially for the second function, because the lambda for that capture variables.
So change these:
void loop_through(void (*)(Tile* t));
void loop_through_limit(Tile* (*)(Tile* t), /*...*/);
to these:
void loop_through(std::function<void(Tile*)> fun);
void loop_through_limit(std::function<Tile*(Tile*)> fun, /*...*/);
Now you can pass lambda to the above functions.
Lambdas are typically implemented as functors (objects with an overloaded operator()). For lambas without captures the standard guarantees that they are implicitely convertible to a function pointer with the same signature (safe, since the lambda functor doesn't contain data). For lambdas with capture that is not safely possible and therefore forbidden.
In order to allow for this you need to change your loop_through and loop_through_limit method to either take std::function<void(Tile*)>:
void loop_through(std::function<void(Tile*)>);
void loop_through_limit(std::function<Tile*(Tile*)> func, int start_x, int start_y, int width, int height);
or to a template function taking any type of executable function object
template<typename F> void loop_through_limit(F func);
template<typename F> void loop_through_limit(F func, int start_x, int start_y, int width, int height);
The later approach has the advantage of lower overhead (no need to construct a std::function object), while the former approach has the advantage of not making the method a template, so it can e.g. still be virtual.
...Then it starts to turn into a "lambda" function instead of just a
"function pointer"...
Thats exactly right, Standard says that lambdas that do not capture anything can be implicitly cast to function pointers with same signature.
That you can do is make loop_through and loop_through_limit templates
template <typename F>
void loop_through(F);
template <typename F>
void loop_through_limit(F, int start_x, int start_y, int width, int height);
and call f inside.
http://pastebin.com/CsViwQFg
I'm using an SDK known as DragonFireSDK and there's a function called TouchAdd() that let's me add a function as a parameter (in this case: MoveLeft() and MoveRight()).
The only problem is, if the function is in a class (in this case, the Player class), I get the following errors:
Player *player;
void AppMain()
{
player = new Player(20,20,10);
tleft = TouchAdd(0,0,180,480,player->MoveLeft,0);
tright = TouchAdd(180,0,180,480,player->MoveRight,0);
}
The error:
error C3867: 'Player::MoveLeft': function call missing argument list; use '&Player::MoveLeft' to create a pointer to member
error C3867: 'Player::MoveRight': function call missing argument list; use '&Player::MoveRight' to create a pointer to member
If you want to pass function as a parameter then syntax is &Player::MoveLeft; as it is not bound to any object such as player.
The DragonFireSDK appears to want a "C" callable function and you're trying to pass a member function (though not using the right syntax). I think you'll need to do something like:
Player *player;
extern "C"
int PlayerMoveLeft(int id, int event, int x, int y)
{
// do something - I'm not sure what might be possible
// to get a pointer or a reference to the player object
// hopefully one or more parameters passed to this callback
// will have the information you need to do that
// or if you only have one global player, you're set -
// just use it
Player* player = /* ??? */;
player->MoveLeft( id, event, x, y); // or whatever needs to be passed
return 0;
}
extern "C"
int PlayerMoveRight(int id, int event, int x, int y)
{
Player* player = /* ??? */;
player->MoveRight( id, event, x, y); // or whatever needs to be passed
return 0;
}
void AppMain()
{
player = new Player(20,20,10);
tleft = TouchAdd(0,0,180,480,PlayerMoveLeft,0);
tright = TouchAdd(180,0,180,480,PlayerMoveRight,0);
}
Note that even though a static member function will often work (since there's no 'hidden' this pointer passed in, strictly speaking you should use non-member extern "C" functions.
Since the function signature of TouchAdd (taken from here) is
int TouchAdd(int x, int y, int width, int height, int (*callback)(int id, int event, int x, int y), int id);
the expected function must be a free function, eg:
int myCallback(int id, int event, int x, int y){
// do your stuff
}
void AppMain(){
tLeft = TouchAdd(....,&myCallback,...);
}
You can't pass a member function pointer (&Player::MoveX), since that function needs to be called on an object of that class (Player). So you need to use a work-around for that:
Player* player;
int PlayerMoveLeft(int id, int event, int x, int y){
return player->MoveLeft(id,event,x,y);
}
int PlayerMoveRight(int id, int event, int x, int y){
return player->MoveRight(id,event,x,y);
}
void AppMain(){
player = new Player(20,20,10);
tLeft = TouchAdd(...,&PlayerMoveLeft,...);
tRight = TouchAdd(...,&PlayerMoveRight,...);
}
}
It seems like id is the custom parameter that gets passed to the callback. If you only have 32-bit targets (and it seems like DragonFireSDK is meant only for iPhone, so I guess the answer is yes), you can cast it to Player* to bind to the player instance.
int PlayerMoveLeft(int id, int event, int x, int y)
{
Player* player = reinterpret_cast<Player*>(id);
return player->MoveLeft(event, x, y);
}
int PlayerMoveRight(int id, int event, int x, int y)
{
Player* player = (Player*)id;
return player->MoveRight(event, x, y);
}
void AppMain()
{
Player* player = new Player(20,20,10);
tleft = TouchAdd(0,0,180,480,PlayerMoveLeft,(int)player);
tright = TouchAdd(180,0,180,480,PlayerMoveRight,(int)player);
}
Even if that doesn't work, or you don't want to use kinda-ugly type casts, you can always have a global or static object with lookup tables. Making PlayerMoveLeft and PlayerMoveRight static members of the Player class may also look nicer, and I think it should play well with TouchAdd().
tleft = TouchAdd(0,0,180,480,player->MoveLeft,0);
tright = TouchAdd(180,0,180,480,player->MoveRight,0);
You're not passsing arguments to MoveLeft and MoveRight functions. I suppose they're function call as the title of your topic says, so you must pass arguments as well IF they take arguments.
If they're don't take argument, then do this:
tleft = TouchAdd(0,0,180,480,player->MoveLeft(),0);
tright = TouchAdd(180,0,180,480,player->MoveRight(),0);
If they're NOT function calls, instead you want to pass the member function pointers, then do this:
tleft = TouchAdd(0,0,180,480, &Player::MoveLeft,0);
tright = TouchAdd(180,0,180,480, &Player::MoveRight,0);
You also need to pass the instance so that member functions can be invoked later on.
It would be better if you let us know the signature of TouchAdd function. So that we can answer more specifically.