6

I have the class

class A
{
public:
    class Key
    {
        Key() {}
        Key(Key const &) {}
    };

    A(Key key, int a = 5) {}
};

The constructor for Key is private, so no one should be able to construct an object A. However, with the following code:

int main() {
    A a(A::Key()); // this compiles !!!
    A a2(A::Key(), 5); // this doesn't
    // somehow defaulting the argument causes the private constructor
    // to be OK - no idea why
    return 0;
}

By making use of the default argument for int a in my constructor, the compiler happily compiles my usage of A::Key() despite the fact that it is private. If I explicitly give a value for a, though, the compiler correctly recognizes that I am trying to use a private constructor and errors out. Why is this? Is there someway to force the compiler to error out for the first example as well?

See here for live example.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
R_Kapp
  • 2,818
  • 1
  • 18
  • 32

1 Answers1

7

This is because of the most vexing parse.

A a(A::Key());

Does not create a A named a and construct it with a temporary A::Key. It creates a function a that returns an A and takes an unnamed pointer to function that returns a A::Key.

If you add a pair of parentheses to it you will get a compiler error

A a((A::Key()));

That you are trying to call a private constructor. Alternatively you can use uniformed initialization which also disambiguate it and will cause a compile error

A a(A::Key{});
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • 1
    I knew I'd seen this somewhere before... one of those things I run into once every 5 years and am flummoxed by because I haven't seen it in so long... Thanks for the help. – R_Kapp Sep 29 '17 at 16:00
  • 1
    @R_Kapp No problem, glad to help. – NathanOliver Sep 29 '17 at 16:03