I am trying to create a pointer to a member function which has default arguments. When I call through this function pointer, I do not want to specify an argument for the defaulted argument. This is disallowed according to the standard, but I have never before found anything that the standard disallowed that I could not do in some other conformant way. So far, I have not found a way to do this.
Here is code illustrating the problem I'm trying to solve:
class MyObj
{
public:
int foo(const char* val) { return 1; }
int bar(int val = 42) { return 2; }
};
int main()
{
MyObj o;
typedef int(MyObj::*fooptr)(const char*);
fooptr fp = &MyObj::foo;
int r1 = (o.*fp)("Hello, foo.");
typedef int(MyObj::*barptr)(int);
barptr bp1 = &MyObj::bar;
int r2 = (o.*bp1)(); // <-- ERROR: too few arguments for call
typedef int (MyObj::*barptr2)();
barptr2 bp2 = &MyObj::bar; // <-- ERROR: Can't convert from int(MyObj::*)(int) to int(MyObj::*)(void)
int r3 = (o.*bp2)();
return 0;
}
Any ideas on how to do this in conformant C++ if I do not want to specify any values for the defaulted arguments?
EDIT: To clarify the restrictions a bit. I do not want to specify any default arguments either in the call or in any typedef. For example, I do not want to do this:
typedef int(MyObj::*barptr)(int = 5);
...nor do I want to do this:
typedef int(MyObj::*barptr)(int);
...
(o.barptr)(5);
A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn't provide a value for the argument. In case any value is passed, the default value is overridden.
Using a pointer-to-member-function to call a function Calling the member function on an object using a pointer-to-member-function result = (object. *pointer_name)(arguments); or calling with a pointer to the object result = (object_ptr->*pointer_name)(arguments);
Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, (since C++11) and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations.
Constructors cannot have default parameters.
It would be rather strange to expect the function pointers to work the way you expect them to work in your example. "Default argument" is a purely compile-time concept, it is a form of syntactic sugar. Despite the fact that default arguments are specified in the function declaration or definition, they really have nothing to do with the function itself. In reality default arguments are substituted at the point of the call, i.e. they are handled in the context of the caller. From the function's point of view there's no difference between an explicit argument supplied by the user or a default one implicitly supplied by the compiler.
Function pointers, on the other hand, are run-time entities. They are initialized at run time. At run-time default arguments simply don't exist. There's no such concept as "run-time default arguments" in C++.
Some compilers will allow you to specify default arguments in function pointer declaration, as in
void foo(int);
int main() {
void (*pfoo)(int = 42) = foo;
pfoo(); // same as 'pfoo(42)'
}
but this is not standard C++ and this does not appear to be what you are looking for, since you want the "default argument " value to change at run time depending on the function the pointer is pointing to.
As long as you want to stick with genuine function pointers (as opposed to function objects, aka functors) the immediate workaround would be for you to provide a parameter-less version of your function under a different name, as in
class MyObj
{
public:
...
int bar(int val = 42) { return 2; }
int bar_default() { return bar(); }
};
int main()
{
MyObj o;
typedef int (MyObj::*barptr2)();
barptr2 bp2 = &MyObj::bar_default;
int r3 = (o.*bp2)();
return 0;
}
This is, of course, far from elegant.
One can actually argue that what I did above with bar_default
could have been implicitly done by the compiler, as a language feature. E.g. given the class definition
class MyObj
{
public:
...
int bar(int val = 42) { return 2; }
...
};
one might expect the compiler to allow the following
int main()
{
MyObj o;
typedef int (MyObj::*barptr2)();
barptr2 bp2 = &MyObj::bar;
int r3 = (o.*bp2)();
return 0;
}
where the pointer initialization would actually force the compiler to implicitly generate an "adapter" function for MyObj::bar
(same as bar_default
in my previous example), and set bp2
to point to that adaptor instead. However, there's no such feature in C++ language at this time. And to introduce something like that would require more effort than it might seem at the first sight.
Also note that in the last two examples the pointer type is int (MyObj::*)()
, which is different from int (MyObj::*)(int)
. This is actually a question to you (since you tried both in your example): how would you want it to work? With an int (MyObj::*)()
pointer? Or with a int (MyObj::*)(int)
pointer?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With