C++ messed up: optional argument forced to be mand

2019-08-27 00:16发布

问题:

I want to have a function with optional argument. However, VC++ is throwing an error I cannot comprehend. The code is as simple as follows:

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

void myFunction(string something, int w);

int main()
{
    myFunction("a string");

    int a = 1;
}

void myFunction(string something, int w = 5)
{
    cout << something << " - " << w << endl;
}

It complains:

'myFunction': function does not take 1 arguments

However if I move myFunction() before main(), it gives no error. What is going on? Please help. Thank you.

回答1:

This error is because you have optional variables when you call your function, but not in your declaration.

This will create a function with two variables:

void myFunction(string something, int w);

However, this would make the second variable optional:

void myFunction(string something, int w=5);

You need to make the declaration have a optional variable.

Also, I am surprised your compiler didn't try to spit some sort of error relating to a redefinition. (That might even be a compiler bug! I will update on research into this. Update: Doesn't seem like compiler bug, but definitely a feature I would love to have. Even if it was a bug, it would be linker related.)



回答2:

Some terminology: This

void myFunction(string something, int w);

is a declaration. This

void myFunction(string something, int w) {
    // note the function body
}

is usually called a definition. But it’s really both, a definition as well as a declaration. For simplicity I’ll keep calling it the definition.

Your problem is that order matters, specifically the order in which you declare, define and call your function. At the call site in main() the only visible declaration of myFunction takes a string and an integer and has no default arguments. The definition is not visible at that point, so it doesn’t come into play at all. For the compiler it looks like you attempt to call a function that doesn’t exist.

There are two solutions:

  1. Move the default argument from the definition to the declaration. That’s the common way to do it. In most cases you have the declaration (including any default arguments) in a header file and a matching definition (without the default arguments) in a cpp file that #includes the header.
  2. Get rid of the declaration and move the definition above main(). This works because the definition is also a declaration.

In this simple example both are equally valid.

For the definition default arguments are irrelevant. It doesn’t matter if you get the 5 because someone typed it explicitely at the call site or if the compiler added it via the default argument. That’s why, when you have a separate declaration and definition, the default argument is only necessary for the declaration. You can and should leave it out of the definition. Otherwise you have to maintain it in two places for no good reason.