C++ function ptr with class

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
p_lu
Knows some wx things
Knows some wx things
Posts: 29
Joined: Thu Oct 25, 2018 2:04 pm

C++ function ptr with class

Post by p_lu »

Hi,

This is a generic C++ programming issue, not anything wxWidgets specific. I just don't know
where to ask for C++ help.

The following sample program fails to compile under VS2017, with the following errors (for
the noted line)...

E0109 expression preceding parentheses of apparent call must have (pointer-to-) function type
C2064 term does not evaluate to a function taking 1 arguments

It should be a "straight-forward" function pointer call, but somehow the inclusion of class
requires a different syntax from the non-class case.

Thanks for any and all help.


Code: Select all

=== Sample program.

class wxCommandEvent
{
};


void globalClick(wxCommandEvent &)
{
}


class ControlFrame
{
public:
        void OnButton3Click(wxCommandEvent &);
	void OnButton4Click(wxCommandEvent &);
};

void ControlFrame::OnButton3Click(wxCommandEvent& event)
{
}

void ControlFrame::OnButton4Click(wxCommandEvent& event)
{
}

int main()
{
	wxCommandEvent ev;

	void(*funcClick[])(wxCommandEvent &) = {
		&globalClick
	};
	funcClick[0](ev);  // This works


	void (ControlFrame::*funcButtonClick[])(wxCommandEvent&) = {
		&ControlFrame::OnButton3Click, &ControlFrame::OnButton4Click
	};

	funcButtonClick[0](ev); // *** This fails ***

	return 0;
}
Last edited by doublemax on Tue Mar 12, 2019 10:58 pm, edited 1 time in total.
Reason: Added code tags
User avatar
doublemax
Moderator
Moderator
Posts: 19117
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: C++ function ptr with class

Post by doublemax »

Non-static member functions always need an instance of the class. Otherwise, what would "this" point to inside the method?

Code: Select all

ControlFrame *p = new ControlFrame();
(p->*funcButtonClick[0])(ev); // *** This should compile ***
http://www.newty.de/fpt/fpt.html#defi
Use the source, Luke!
p_lu
Knows some wx things
Knows some wx things
Posts: 29
Joined: Thu Oct 25, 2018 2:04 pm

Re: C++ function ptr with class

Post by p_lu »

I realized this after doing some additional Web-searching and compiling the program under g++, which gave a more "meaningful" error message.

funcptr.cpp: In member function ‘void clx::f()’:
funcptr.cpp:38:30: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((clx*)this)->clx::funcButtonClick[0] (...)’, e.g. ‘(... ->* ((clx*)this)->clx::funcButtonClick[0]) (...)’

Some article stated that C++ chose not to have non-static member functions to have a form that allows explicit passing of "this" (as static members always do). This makes function pointers with classes somewhat "useless," even if an instance of the class exists because it can't be used.

So, does this mean there is no way a call-by-pointer via a "table" would work in the context of classes (with non-static functions), as the table set up thus?...

void (ControlFrame::*funcButtonClick[])(wxCommandEvent&) = {
&ControlFrame::OnButton3Click, &ControlFrame::OnButton4Click
};

BTW, in my "real" code, the function dispatch part _is_ within the ControlFrame class, so "this" is already there, but the compiler insisted that the function table has the "ControlFrame::" designations included.

There were some other article that talked about some other mechanisms to do table/data-driven function calling, but the descriptions were a little too over-my-head.

I'll convert my calls to use a switch, but it's not as as clean/concise as a table-driven method.

switch(n) {
case 0: OnButton3Click(ev); break;
case 1: OnButton4Click(ev); break;
}


Thank you so much for the response and help.

*** PS ***

Since "this" exists (in my "real" code),

(this->*funcButtonClick[0])(ev);

compiles and works as you stated.

Thank you again.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7460
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: C++ function ptr with class

Post by ONEEYEMAN »

Hi,
Usually, www.stackoverflow.com is a good place to ask for such questions...

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19117
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: C++ function ptr with class

Post by doublemax »

SO is a very toxic place though. They're like the SJWs of programming ;)
Use the source, Luke!
p_lu
Knows some wx things
Knows some wx things
Posts: 29
Joined: Thu Oct 25, 2018 2:04 pm

Re: C++ function ptr with class

Post by p_lu »

Sorry, but I don't know how to set up the code below in a code-display scroll section (<code>, <code/> ???), so am just including the code in-line.

I've rearranged the code a little, so the dispatcher is part of the ControlFrame class. The code in dispatcher() compiles and runs fine.
One would think the code in dispatcher1(), under SHOULD_WORK, which simply takes the explicit "ControlFrame::" and "this->" out would work as well, since dispatcher1() is part of ControlFrame. The class-based dispatcher1() code, as written, would be analogous to the no-class global dispatch done in main().

Any idea why the dispatch1() coding "style" that uses implicit "ControlFrame::" is not allowed? Is this just another arbitrary choice made by the C++ designers?

Thanks for any insight.

Code: Select all

class wxCommandEvent
{
};


void globalClick(wxCommandEvent &)
{
}


class ControlFrame
{
public:
    void OnButton3Click(wxCommandEvent &);
    void OnButton4Click(wxCommandEvent &);

    void dispatcher(unsigned int);
    void dispatcher1(unsigned int);
};

void ControlFrame::OnButton3Click(wxCommandEvent& event)
{
}

void ControlFrame::OnButton4Click(wxCommandEvent& event)
{
}

    
void ControlFrame::dispatcher(unsigned int n)
{
    void (ControlFrame::*funcButtonClick[2])(wxCommandEvent&) = {
        &ControlFrame::OnButton3Click, &ControlFrame::OnButton4Click
    };

    wxCommandEvent ev;
    if (n < 2)
        (this->*funcButtonClick[n])(ev);
};

void ControlFrame::dispatcher1(unsigned int n)
{
#ifdef SHOULD_WORK
    void (*funcButtonClick[2])(wxCommandEvent&) = {
        &OnButton3Click, &OnButton4Click
    };

    wxCommandEvent ev;
    if (n < 2)
        (*funcButtonClick[n])(ev);
#endif
};

int main()
{
    wxCommandEvent ev;

    void(*funcClick[])(wxCommandEvent &) = {
        &globalClick
    };
    funcClick[0](ev);

    ControlFrame cf;
    cf.dispatcher(0);
    cf.dispatcher1(0);
    
    return 0;
}
User avatar
doublemax
Moderator
Moderator
Posts: 19117
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: C++ function ptr with class

Post by doublemax »

[I'm not sure about this answer, i couldn't find a proper documentation for this either (although i'm sure it exists).]

I think inside a class method you can access members of the class (like variables and methods) without the "this", where you could also use "this->".

A member variable "m_string" can be accessed with "this->m_string" or just "m_string".
The same goes for method calls.

But in your example, you could not replace "ControlFrame::" with "this->".

I know the explanation is a little weak. If someone has a better, "official" explanation, i'd be interested to hear it myself.

BTW: What exactly are you trying to achieve? I have a feeling there could be an easier way.
Use the source, Luke!
Kvaz1r
Super wx Problem Solver
Super wx Problem Solver
Posts: 357
Joined: Tue Jun 07, 2016 1:07 pm

Re: C++ function ptr with class

Post by Kvaz1r »

p_lu wrote: Thu Mar 14, 2019 12:50 pm Any idea why the dispatch1() coding "style" that uses implicit "ControlFrame::" is not allowed? Is this just another arbitrary choice made by the C++ designers?
Not an expert, but here some answers:
And such call as in code above won't work because your array not a member of class so this-pointer can't know anything about it.

I guess it also can be useful link - Pointer declaration
p_lu
Knows some wx things
Knows some wx things
Posts: 29
Joined: Thu Oct 25, 2018 2:04 pm

Re: C++ function ptr with class

Post by p_lu »

>>> But in your example, you could not replace "ControlFrame::" with "this->".

Not sure what you're thinking with the above statement.

The difference between dispatcher() and dispatcher1() is simply that in the latter
case, the explicit qualifiers "ControlFrame::" and "this->" were removed. This
should be acceptable to the compiler, since dispatcher1() is indeed a non-static
member function of the ControlFrame class (the syntax is not ambiguous).

I'm simply implementing a function-call dispatcher based on some integer index.
The dispatch could be done with a table of function pointers or via a switch
statement [ example given in previous post ]. The number of functions that
could be dispatched could be very large, and hence a table or switch mechanism
is highly desirable (or somewhat less desirable, if.. else if... else if).

Thanks for inputs.
User avatar
doublemax
Moderator
Moderator
Posts: 19117
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: C++ function ptr with class

Post by doublemax »

p_lu wrote: Thu Mar 14, 2019 5:22 pm >>> But in your example, you could not replace "ControlFrame::" with "this->".

Not sure what you're thinking with the above statement.
I meant in this code:

Code: Select all

    void (ControlFrame::*funcButtonClick[2])(wxCommandEvent&) = {
        &ControlFrame::OnButton3Click, &ControlFrame::OnButton4Click
    };
You could not replace "&ControlFrame::OnButton3Click" with "&this->OnButton3Click" and it would still work.

I think it could have something to do with virtual methods. The address of the method "ControlFrame::OnButton3Click" is unique, it has a fixed position in memory. But the address of just "OnButton3Click" is not, if you subclass ControlFrame and override it, two of these functions exist in memory and the actual method that gets called depends on the instance.
Use the source, Luke!
p_lu
Knows some wx things
Knows some wx things
Posts: 29
Joined: Thu Oct 25, 2018 2:04 pm

Re: C++ function ptr with class

Post by p_lu »

>>> You could not replace "&ControlFrame::OnButton3Click" with "&this->OnButton3Click" and it would still work.

Well, the compiler wouldn't accept "&this->OnButton3Click" anyway. I'm not clear that what you claim, that "this" is polymorphic (inherited class, virtual class, etc.) makes it "unusable." When the dispatch table is encountered, "this" has a very clear "meaning," whether it's "ControlFrame" or "ControlFrameSuperclass" or whatever. At any point, the compiler _has_ to know what "this" is (can't be ambiguous) or the entire scheme of things breaks down.

Correct me if you disagree...

Regardless of whether &ControlFrame:: or &this-> is used/usable, the entry in the table (e.g., &ControFrame::OnButton3Click) is meant to specify a (non-static) class method along with the instance of the class. Perhaps the requirement for explicity using "ControlFrame::" is to tell the compiler this "pointer" includes both the pointer to the method and the pointer to the class instance (which may be kept "blank" until actual use, since one could conceivable do a call using (someOtherControlFrameClassInst->*funcButtonClick[0])(ev) rather than (this->*funcButtonClick[0])(ev) ).


Going back to the old discussion about code in dispatcher1()...

I still think the "shorthand" of not using "ControlFrame::" and "this->" should work (is not ambiguous), since the compiler/syntax should be able to tell that by "OnButton3Click" we mean "ControlFrame::OnButton3Click' (or whatever the class of "this" is at that time). It's not much different from using namespaces, where "string" may mean "std::string." And, in the case of (trying to use) someOtherControlFrameClassInst->*funcButtonClick[0], the "someOtherControlFrameClassInst" has to have the same class as "this."

The only thing in doing "shorthand" is that the definition of funcButtonClick[] would have to use "inferred" type based on the right-hand-side quantity/ies, in the same way as auto variables. The type of funcButtonClick[] (meant to be "ControlFrame::funcButtonClick[]) would have to be inferred from the items on the right ("OnButton3Click," shorthand for "ControlFrame::OnButtonClick3")...

auto funcButtonClick[] = { // the "auto" is just to clarify that funcButtonClick may not be a straight/simple func ptr
&OnButton3Click, &OnButton4Click
};

When the compiler figures out that &OnButton3Click really means &this->OnButton3Click (or &ControlFrame::OnButton3Click, given "this" is of class "ControlFrame"), it "types" "funcButtonClick" accordingly (to "void (ControlFrame::*funcButtonClick)(wxCommandEvent &)").

I still think the "shorthand" form is much more straight-forward (analogous to the table dispatch for global, no-class, functions), were it allowed. The requirement for the explicit "ControlFrame::" and "this->" prefixes really confuses things [and makes things less portable, or higher maintenance, as when/if ControlFrame is renamed to NewControlFrame and what could have been implicit now needs code editing because it is explicit].
User avatar
doublemax
Moderator
Moderator
Posts: 19117
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: C++ function ptr with class

Post by doublemax »

I do agree that the compiler could theoretically use an implicit "ControlFrame::" for the method names, but i also believe there is probably a technical reason that it doesn't. I just don't know which one.

But i'm out of my comfort zone here, i just don't know enough about this topic.

Maybe that is something you could ask on Stackoverflow, i'd be interested in the answer myself.
Use the source, Luke!
Post Reply