Why can't a typedef of a function be used to define a function?
Asked Answered
C

4

12

From § 8.3.5.11 of ISO/IEC 14882:2011(E):

A typedef of function type may be used to declare a function but shall not be used to define a function

The standard goes on to give this example:

typedef void F();
F fv; // OK: equivalent to void fv();
F fv { } // ill-formed
void fv() { } // OK: definition of fv

What motivates this rule? It seems to limit the potential expressive usefulness of function typedefs.

Counterplot answered 25/7, 2013 at 4:25 Comment(4)
Think of this: typedef creates an alias for another type, which, in your case, a function type. With the third (ill-formed) example, would F mean as the return type of the function or the type of the function itself?Viscountcy
@MarkGarcia: It would be the type of the function itself, since there are no parentheses delimiting the parameters. In other words, it could be resolved unambiguously if the language allowed it; it just doesn't.Lanfranc
@KeithThompson That statement gave me some idea. Well, what about the function parameters? How would you refer to the function parameters if you define the function in that way?Viscountcy
@MarkGarcia: Yup; see my answer.Lanfranc
L
13

Though this question is about C++, but since C++ inherits typedef and function pointer from C, so an explanation of the same question in C can be used in here. There's a formal explanation for C.

Rationale for International Standard - Programming Languages C §6.9.1 Function definitions

An argument list must be explicitly present in the declarator; it cannot be inherited from a typedef (see §6.7.5.3). That is to say, given the definition:

typedef int p(int q, int r);

the following fragment is invalid:

p funk // weird
{ return q + r ; }

Some current implementations rewrite the type of, for instance, a char parameter as if it were declared int, since the argument is known to be passed as an int in the absence of a prototype. The Standard requires, however, that the received argument be converted as if by assignment upon function entry. Type rewriting is thus no longer permissible.

Langevin answered 25/7, 2013 at 5:5 Comment(2)
I would like to see a similar Rationale document for the C++ Standard. Is there one? (Until now the best approaching I've read are Stroustrup's books...)Exemption
@Exemption Not to my knowledge. I would love to see one, too.Langevin
L
8

It's probably mostly historical reasons. typedef was a relatively late addition to C, and was tacked onto the existing language (and caused a few problems for the parsing phase of compilers).

Also, a function definition has to define the names of the parameters, if any. A function type includes the function's return type and parameter types, but not its parameter names. For example, these:

void (int)
void (int x)
void (int y)

are three ways of writing the same function type. If you had:

typedef void func_t(int);

then this hypothetical definition:

func_t some_func { }

wouldn't define a name for its int parameter. I'm not sure how that could have been resolved in a reasonable manner. It would be possible, I suppose, but it was never done.

But the bottom line is probably just that Dennis Ritchie either didn't think it was worth the effort to define how a typedef could be used in a function definition, or he simply didn't think of it.

Lanfranc answered 25/7, 2013 at 4:45 Comment(3)
But it's perfectly okay to have nameless parameters, and simply be unable refer to them. So your hypothetical would be the same as writing void some_func(int) { }Jermayne
@BenjaminLindley: Yes, but it would mean that no function defined via a typedef could have named parameters. That would be an annoying and arbitrary restriction. It's not worth permitting one special case without being able to generalize it. And C, where typedefs originated, doesn't permit nameless parameters in function definitions.Lanfranc
Didn't know that about C.Jermayne
P
1

Let me put a few words. Consider a statement:

typedef void F(int p1, char* p2);

This statement assigns name F to a function signature void (int, char*); This is definition of an alias to the function signature. After that the statement:

F fv;

tells that there is a function fv. It has the signature that was mentioned above and it has its body somewhere. Look at the C/C++ syntax of the function definition:

retType  funcName(params) { body }

There are actually 2 names used retType and funcName. None of them are the same to the name F from the initial typedef. The name F has meaning of both names. If language would allow something like:

F { body }

this will associate body with the function type. But this leads a problem:

The meaning of F would be not clear. Is it an "alias to the function signature" or is it a "name of the entry point into a code"?

Plus the syntax of the last example would be weird to millions of C/C++ programmers.

Pontiff answered 25/7, 2013 at 8:20 Comment(0)
L
-4

The rule is as you quoted - typedef of function type shall not be used to define a function. In the 3rd line of the example, you are trying to define a function with function type F. This is not allowed by the standard.


EDIT
As you pointed out, I try to explain more on it.

For the 3rd line, if it were legal, then you could replace F with the typedef definition:
void fv { }(). This is not a legal definition or declaration in C++.

I think the key point is that typedef is just creating an alias for simplification, and you can replace your typedef type like replacement of #define during compilation.

Lozada answered 25/7, 2013 at 4:33 Comment(8)
But what motivates this rule?Incarnadine
I think he knows the rule is as quoted. He's the one who quoted it, and gave chapter and verse.Jermayne
@MartinDrozdik for the 3rd line, if it were legal, then you could replace F with the typedef definition: void fv { }(). This is not a legal definition or declaration in C++Lozada
@BenjaminLindley I re-edit my post. You could have a look and point out any suggestions.Lozada
You're just telling him what the standard says. Which he already knows. He quoted it in his question. He's asking for the reason the standard rule is written that way. I have no suggestions, because I don't know the reason for the rule.Jermayne
You're still just re-stating the fact that it's not valid. If it were, then F fv { } would be valid.Lanfranc
@KeithThompson No, illegal. If it were, the compile treat v {} as a whole. Integrate it into typedef, it will be void fv {}(). How is this legal?Lozada
Typedefs are not macros; they aren't just substituted textually. If the language permitted typedefs in function definitions, then this: typedef void F(); F func { }; would be legal, and equivalent to void func() { }. Parameter names, as I discuss in my answer, are (I think) the main obstacle.Lanfranc

© 2022 - 2024 — McMap. All rights reserved.