Why does C++ code missing a formal argument name in a function definition compile without warnings?

While getting started with some VS2005-generated MFC code, I noticed it overrode a method with something like this:

void OnDraw(CDC* /*pDC*/)
{
    ...
    // TODO: Add your code here
}

So of course, as soon as I added something I realized I needed to un-comment the pDC formal argument in order to compile, but I'm confused as to how/why a C++ function can compile (with no warnings) when the formal argument only has a type and not a name:

void foo(int)
{
    int x = 3;
}
int main()
{
    foo(5);
    return 0;
}

Shouldn't this generate at least a warning (with -Wall or /W4)? It doesn't seem to. Am I missing something? Is there a case where this is useful or is it just because the compiler can't tell the difference between a function declaration (only types required) and a definition (fully specified) until after the line has been processed?


Solution 1:

Because sometimes you have a parameter that's required by an interface but the function doesn't use it. Maybe the parameter is no longer necessary, is only necessary in other functions that must use the same signature (especially so they can be called through pointers) or the functionality hasn't been implemented yet. Having parameters that aren't used can be particularly common in generated or framework code for this reason (and that's probably why the MFC generated code has the name commented out).

As to why there's no warning - I guess it's because whether this is a problem is a subjective thing and other people (particularly compiler implementers) don't see it as a problem. Once you actually go to use the parameter, you'll get the compiler to complain if you forget to uncomment the name so you get the compiler complaining only when you really need it to (the compiler's version of the agile YAGNI: "You Aren’t Gonna Neet It" philosophy).

The opposite does seem to generally occur when you crank up warnings - named parameters that aren't used generate warnings - again that's probably why the generated function has the name commented out.

Solution 2:

The most common reason I've seen is to suppress the unused variable warnings the compiler will throw up for:

#include <iostream>

void foo(int source)
{
  std::cout << "foo()" << std::endl;
}

int main()
{
  foo(5);
  return 0;
}

gcc says: main.cc:3: warning: unused parameter 'source'

There are two common ways to get rid of the warning: comment the variable name or remove it entirely:

void foo(int /*source*/)
{
  std::cout << "foo()" << std::endl;
}

versus

void foo(int)
{
  std::cout << "foo()" << std::endl;
}

I highly recommend commenting over removing. Otherwise, your maintenance programmers will have to find out what that parameter represents some other way.

Qt (and probably other frameworks) provides a macro that suppresses the warning without needed to comment or remove the variable name: Q_UNUSED(<variable>):

void foo(int source)
{
  Q_UNUSED(source); // Removed in version 4.2 due to locusts
  std::cout << "foo()" << std::endl;
}

This lets you call out in the function body that the variable is not used, and gives a great place to document why it isn't used.

Solution 3:

C++11 N3337 standard draft

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf says it is legal at 8.4.1/6 "Function definitions > In general":

Note: Unused parameters need not be named. For example,

void print(int a, int) {
    std::printf("a = %d\n",a);
}

More precisely, 8.4.1/1 says that the grammar for function definitions is

function-definition:
    attribute-specifier-seqopt decl-specifier-seqopt
    declarator virt-specifier-seqopt function-body

Then if you follow the grammar definitions, e.g. under "Annex A Grammar summary", you will see that the names are optional.