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.

Shea Levy
  • 5,237
  • 3
  • 31
  • 42
  • 1
    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? – Mark Garcia Jul 25 '13 at 04:31
  • 2
    @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. – Keith Thompson Jul 25 '13 at 04:36
  • 2
    @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? – Mark Garcia Jul 25 '13 at 04:39
  • @MarkGarcia: Yup; see my answer. – Keith Thompson Jul 25 '13 at 04:48

4 Answers4

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.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 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...) – gx_ Jul 25 '13 at 06:44
  • @gx_ Not to my knowledge. I would love to see one, too. – Yu Hao Jul 25 '13 at 07:05
7

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.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 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) { }` – Benjamin Lindley Jul 25 '13 at 04:55
  • 2
    @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. – Keith Thompson Jul 25 '13 at 04:59
  • 1
    Didn't know that about C. – Benjamin Lindley Jul 25 '13 at 05:04
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.

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
-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.

Zachary
  • 1,633
  • 2
  • 22
  • 34
  • But what motivates this rule? – Martin Drozdik Jul 25 '13 at 04:34
  • I think he knows the rule is as quoted. He's the one who quoted it, and gave chapter and verse. – Benjamin Lindley Jul 25 '13 at 04:34
  • @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++ – Zachary Jul 25 '13 at 04:38
  • @BenjaminLindley I re-edit my post. You could have a look and point out any suggestions. – Zachary Jul 25 '13 at 04:43
  • 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. – Benjamin Lindley Jul 25 '13 at 04:46
  • You're still just re-stating the fact that it's not valid. If it were, then `F fv { }` *would* be valid. – Keith Thompson Jul 25 '13 at 04:47
  • @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? – Zachary Jul 25 '13 at 04:51
  • 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. – Keith Thompson Jul 25 '13 at 04:57