21

Example: Is this legal C++14?

#include <iostream>

static int d() {
    return 42;
}

static int e(int d = d()) {
    return d;
}

int main() {
    std::cout << e() << " " << e(-1) << std::endl;
}

g++ 5.4 with -std=c++14 likes it, but clang++ 3.8 with -std=c++14 complains:

samename.cxx:3:23: error: called object type 'int' is not a function or function pointer
static int e(int d = d()) {return d;}
                     ~^
Casey
  • 10,297
  • 11
  • 59
  • 88
not-a-user
  • 4,088
  • 3
  • 21
  • 37
  • also reproducible with clang 3.9.1 http://melpon.org/wandbox/permlink/8RCXqcgCZzbN7l5o – user1810087 Feb 17 '17 at 11:18
  • Maybe duplicate of http://stackoverflow.com/questions/334882/must-default-function-parameters-be-constant-in-c – Ashwani Feb 17 '17 at 11:18
  • 2
    My common sense tells me clang is right in this situation, as the `d` parameter shadows the `d` global function. Don't quote me on this though. – DeiDei Feb 17 '17 at 11:22
  • 3
    I think @DeiDei is right: `static int e(int d = ::d()) {return d;}` compiles. see [here](http://melpon.org/wandbox/permlink/1Ip3mTE8YKRdte6A) – user1810087 Feb 17 '17 at 11:23
  • Looks like GCC is wrong here. Could you file a bug report? – underscore_d Feb 17 '17 at 13:54
  • 2
    I used to find these questions interesting, but now my first reaction is.. who cares? Such code wouldn't pass review anyway. Pick a better name for your variables and functions. – Lightness Races in Orbit Feb 17 '17 at 17:51

2 Answers2

16

From basic.scope.pdecl/1:

The point of declaration for a name is immediately after its complete declarator and before its initializer (if any), except as noted below.

Example:

unsigned char x = 12;
{ unsigned char x = x; }

Here the second x is initialized with its own (indeterminate) value.

Clang is consistent with this section of the standard. GCC only seems to apply it in {block}.

Given:

constexpr int d() {return 42;}

The following fails in Clang, but works in GCC:

static int e(int d = d()) {return d;}
             // This ^^d should refer to the new name that shadows ::d()

The following fails both in Clang and GCC:

void func(){
    int d = d();
         // ^^d here refers to the new name that shadowed ::d();
 }
garrettmurray
  • 3,338
  • 1
  • 25
  • 23
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • 1
    Are we sure that this applies to default arguments? There are a few ways in which those differ from bog-standard initialisations. Basically: is this really an initializer? – Lightness Races in Orbit Feb 17 '17 at 17:51
  • 1
    @LightnessRacesinOrbit, *"is this really an initializer?"* - As per [this](http://eel.is/c++draft/dcl.fct.default#1), I'll say yes, it is. – WhiZTiM Feb 17 '17 at 18:40
11

It seems it is not legal: see the C++14 specification (section 3.3.2 - Point of declaration).

int x = 5;
{ int x = x; } // second x is initialized with its own undetermined state
{ int x[x]; }  // declares an array with 5 elements, since the declaration of 
               // second x is not complete when the first x is used

In your case, the declaration of d is complete, so when you use d() you're referring to the variable, not the function.

cbuchart
  • 10,847
  • 9
  • 53
  • 93