7

I was writing a function foo() which takes 2 const char*s as arguments, pBegin and pEnd. foo() is passed a null terminated string. By default pEnd points to \0 (last character) of the string.

void foo (const char *pBegin,
          const char *pEnd = strchr(pBegin, 0))  // <--- Error
{
  ...
}

However, I get an error at above line as:

error: local variable ‘pBegin’ may not appear in this context

Why compiler doesn't allow such operation ? What's the potential problem ?

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    Different calling conventions push parameters in different orders. Some typical ones (`cdecl`, `stdcall`) push right-to-left, so in your example `pEnd` would need to be evaluated before `pBegin`, which I don't think makes sense... Have a squiz here: http://en.wikipedia.org/wiki/X86_calling_conventions – Darren Engwirda Feb 05 '12 at 03:57

4 Answers4

10

The standard not only explicitly disallows the use of other parameters in a default argument expression, but also explains why and gives an example:

ISO/IEC 14882:2003(E) - 8.3.6 Default arguments [dcl.fct.default]

9. Default arguments are evaluated each time the function is called. The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in default argument expressions, even if they are not evaluated. Parameters of a function declared before a default argument expression are in scope and can hide namespace and class member names. [Example:

    int a;
    int f(int a, int b = a);         // error: parameter a
                                     // used as default argument
    typedef int I;
    int g(float I, int b = I(2));    // error: parameter I found
    int h(int a, int b = sizeof(a)); // error, parameter a used
                                     // in default argument

—end example] ...

In silico
  • 51,091
  • 10
  • 150
  • 143
  • 1
    The last example may look overly strict. We know sizeof(a) == sizeof(int) regardless of the value of a. The argument of evaluation order doesn't apply, so this case _could_ be allowed. But g++ 4.8.2 raises the expected error. I guess this is in the interest of keeping the rules simple. – Quigi Mar 06 '17 at 00:42
  • Agreed. Also template parameters seem to count as parameters in that sense since recent versions of g++. For example, template void g(T x=default_value()) is an error. This is an annoyance. – André Aichert May 27 '23 at 16:23
6

The language still offers a way to do what you want - use overloaded functions:

void foo (const char *pBegin, const char *pEnd)
{
   //...
}

void foo (const char *pBegin)
{ foo(pBegin, strchr(pBegin, 0)); }
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
3

When the function is called the default arguments are evaluated, but the order they are evaluated is not defined by the C++ standard. That means that you can't reference other parameters in a default argument because they may not have a known value yet.

Neal
  • 6,722
  • 4
  • 38
  • 31
1

You can't use a local variable in a default argument value.

Quote from here:

The standard tells us that the default argument is simply an expression. There are some things that are no allowed (using local variables, using the keyword 'this') but pretty much anything else can serve as a default argument.

Maggie
  • 1,546
  • 16
  • 27