Omitting function default args when no prototype is available?

A

Andy Lomax

gcc 3.3 allowed a typedef for a function pointer to contain default
argument specifications; for example:

typedef int (*foo) (int, int, int=0, bar=0);

However, it turns out that this is illegal and gcc 3.4 prohibits it.
Problem: I've got a lot of code that uses this 'feature', and I can't
move the default specifications into the function declaration or
definition, because they're not visible. This means that I can no
longer call foo-type functions without supplying all the arguments,
which is causing me problems. In addition, I can't even find a
workaround that compiles.

The current situation is that I have a library which has:

typedef int (*foo) (int, int, int=0, bar=0);
class A {
...
foo user_func;

A(foo user_func_) :
user_func(user_func_) {...}
};

The library user supplies 'user_func_', and I call 'user_func' in the
library code with a variable number of parameters, using the defaults.
Within the library itself, there are no user_func declarations or
definitions.

The only potential fix I can see is to manually expand out all the
typedefs, but this doesn't work. I would have to write:

class A {
...
int (*user_func) (int, int, int=0, bar=0);

A(foo user_func_) :
user_func(user_func_) {...}
};

gcc doesn't allow this, because I'm declaring a pointer, and not a
function, and so I can't supply defaults.

Any ideas?

Cheers -

AL
 
J

John Carson

Andy Lomax said:
gcc 3.3 allowed a typedef for a function pointer to contain default
argument specifications; for example:

typedef int (*foo) (int, int, int=0, bar=0);

However, it turns out that this is illegal and gcc 3.4 prohibits it.
Problem: I've got a lot of code that uses this 'feature', and I can't
move the default specifications into the function declaration or
definition, because they're not visible. This means that I can no
longer call foo-type functions without supplying all the arguments,
which is causing me problems. In addition, I can't even find a
workaround that compiles.

The current situation is that I have a library which has:

typedef int (*foo) (int, int, int=0, bar=0);
class A {
...
foo user_func;

A(foo user_func_) :
user_func(user_func_) {...}
};

The library user supplies 'user_func_', and I call 'user_func' in the
library code with a variable number of parameters, using the defaults.
Within the library itself, there are no user_func declarations or
definitions.

The only potential fix I can see is to manually expand out all the
typedefs, but this doesn't work. I would have to write:

class A {
...
int (*user_func) (int, int, int=0, bar=0);

A(foo user_func_) :
user_func(user_func_) {...}
};

gcc doesn't allow this, because I'm declaring a pointer, and not a
function, and so I can't supply defaults.

Any ideas?

Wrap the call using the function pointer in an inline function:

int Wrapper (int a, int b, int c=0, bar d =0)
{
user_func(a,b,c,d);
}

and call Wrapper rather than user_func (do whatever renaming of the Wrapper
function and the pointer that you find convenient).
 
A

Andy Lomax

Wrap the call using the function pointer in an inline function:

int Wrapper (int a, int b, int c=0, bar d =0)
{
user_func(a,b,c,d);
}

Thanks, that does seem to be the way to go.

But this raises a more general issue - there seems to be no way to use
a default parameter if you only have a pointer to a function. Test
case below.

Cheers -

AL
-------------------------------------------------
#include <iostream>
typedef void (*foo_t)(int,int,int,int);

void foo(int a, int b, int c=0, int d=0) {
std::cout << a << b << c << d << std::endl;
}

void indirect_foo(foo_t fooptr) {
fooptr(1, 2, 3, 4); // Ok
fooptr(1, 2); // Not Ok: doesn't compile
}

int main() {
indirect_foo(foo);
}
-------------------------------------------------
 
V

Victor Bazarov

Andy said:
[..] this raises a more general issue - there seems to be no way to use
a default parameter if you only have a pointer to a function. [..]

Correct. That is expressly prohibited by the Standard (8.3.6/3).

V
 
A

Andy Lomax

Andy said:
[..] this raises a more general issue - there seems to be no way to use
a default parameter if you only have a pointer to a function. [..]

Correct. That is expressly prohibited by the Standard (8.3.6/3).

V

Thanks Victor - this prompted me to actually download the std. The
answer is in 8.3.5/6: "A typedef of function type may be used to
declare a function", which implies that 8.3.6/3 does implicitly cover
typedefs as well. Work-around example below; this works on gcc 3.4.

Cheers -

AL
-------------------------------------------------------
#include <iostream>
typedef void foo_t (int,int=0,int=0,int=0);

foo_t foo; // declaration of foo: not required here

void foo(int a, int b, int c, int d) {
std::cout << a << b << c << d << std::endl;
}

void indirect_foo(foo_t fooptr) {
fooptr(1, 2, 3, 4); // Ok: outputs '1234'
fooptr(1, 2); // **Ok: outputs '1200'!!**
}

int main() {
indirect_foo(foo);
}
-------------------------------------------------------
 
J

John Carson

Andy Lomax said:
Andy said:
[..] this raises a more general issue - there seems to be no way
to use a default parameter if you only have a pointer to a
function. [..]

Correct. That is expressly prohibited by the Standard (8.3.6/3).

V

Thanks Victor - this prompted me to actually download the std. The
answer is in 8.3.5/6: "A typedef of function type may be used to
declare a function", which implies that 8.3.6/3 does implicitly cover
typedefs as well. Work-around example below; this works on gcc 3.4.

Cheers -

AL
-------------------------------------------------------
#include <iostream>
typedef void foo_t (int,int=0,int=0,int=0);

foo_t foo; // declaration of foo: not required here

void foo(int a, int b, int c, int d) {
std::cout << a << b << c << d << std::endl;
}

void indirect_foo(foo_t fooptr) {
fooptr(1, 2, 3, 4); // Ok: outputs '1234'
fooptr(1, 2); // **Ok: outputs '1200'!!**
}

int main() {
indirect_foo(foo);
}


This is a non-standard gcc extension. It doesn't work with Comeau or VC++.
 
A

Andy Lomax

This is a non-standard gcc extension. It doesn't work with Comeau or VC++.

Are you sure? 5.3.5/6 says:
A typedef of function type may be used to declare a function but shall not be used to define a function (8.4).
[Example:
typedef void F();
F fv; // ok: equivalent to void fv();
F fv { } // illformed
void fv() { } // ok: definition of fv
—end example]

8.3.6/3 says:
A default argument expression shall be specified only in the parameterdeclarationclause
of a function
declaration or in a templateparameter
(14.1).

This indicates, more or less, to me that a typedef of function type is
*equivalent* to a function declaration (see the comment in the
example), and so qualifies under 8.3.6/3.

Under 'C++ extensions', the gcc online help says:
The use of default arguments in function pointers, function typedefs
and and other places where they are not permitted by the standard is
deprecated and will be removed from a future version of G++.

This indicates that someone thought that default args in function
typedefs are illegal. However, what actually happened in the 3.3 ->
3.4 transition was that typedefs of function *pointer* types were
deprecated, but typedefs of function types weren't deprecated... maybe
somebody had second thoughts about what was or wasn't illegal?

The other issue, of course, is that if it was actually illegal,
despite 5.3.5/6, it would make it impossible to do something which is
clearly Very Useful.

Cheers

AL
 
J

John Carson

Andy Lomax said:
Are you sure? 5.3.5/6 says:

You mean 8.3.5/6
A typedef of function type may be used to declare a function but
shall not be used to define a function (8.4). [Example:
typedef void F();
F fv; // ok: equivalent to void fv();
F fv { } // illformed
void fv() { } // ok: definition of fv
-end example]

8.3.6/3 says:
A default argument expression shall be specified only in the
parameterdeclarationclause
of a function
declaration or in a templateparameter
(14.1).

This indicates, more or less, to me that a typedef of function type is
*equivalent* to a function declaration (see the comment in the
example), and so qualifies under 8.3.6/3.

No, read the next sentence from 8.3.6/3 and especially the footnote:

"This means that default arguments cannot appear, for example, in
declarations of pointers to functions, references to functions, or typedef
declarations."

Something that explicit trumps anything you might infer.
Under 'C++ extensions', the gcc online help says:


This indicates that someone thought that default args in function
typedefs are illegal. However, what actually happened in the 3.3 ->
3.4 transition was that typedefs of function *pointer* types were
deprecated, but typedefs of function types weren't deprecated... maybe
somebody had second thoughts about what was or wasn't illegal?

More likely that they haven't got around to changing it yet.
The other issue, of course, is that if it was actually illegal,
despite 5.3.5/6, it would make it impossible to do something which is
clearly Very Useful.

There are thousands of things that are illegal but which, at least in the
opinion of some people, are Very Useful. Designing a language is incredibly
difficult. It isn't enough to have rules that work in simple cases. You need
rules that work (e.g., are free of ambiguities of interpretation) in
situations of arbitrary complexity.
 
A

Andy Lomax

No, read the next sentence from 8.3.6/3 and especially the footnote:

"This means that default arguments cannot appear, for example, in
declarations of pointers to functions, references to functions, or typedef
declarations."

Ah, bu**er. Missed that.

Isn't it time you were out of the office? :)

Cheers -

AL
 
B

Ben Pope

Andy said:
Thanks, that does seem to be the way to go.

But this raises a more general issue - there seems to be no way to use
a default parameter if you only have a pointer to a function. Test
case below.

Isn't this what Alexandrescu's "Generalised Functors" do? OK, so it's not a typedef, but it does have value semantics, so you can use it as a prototype.

Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,084
Latest member
HansGeorgi

Latest Threads

Top