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.
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.
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?...
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;
}
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?
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?
>>> 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).
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.
>>> 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].
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.