10

This story is similar to my previous question. All versions of GCC that support C++11, have this exact behaviour. I could not find any other compiler that struggles with my test case.

The test case:

struct BaseFooWrapper
{
    BaseFooWrapper(int qux)
    { }
};

struct Foo
{
    Foo(BaseFooWrapper & foo)
        : foo(foo)
    { }

    BaseFooWrapper & foo;
};

struct SomeFooWrapper : public BaseFooWrapper
{
    using BaseFooWrapper::BaseFooWrapper;


    Foo foo{*this};
};

int main()
{
    SomeFooWrapper wrapped_foo(1);
    return 0;
}

Live on godbolt.com


This piece of code compiles with clang (3.4 through 4.0), icc (16, 17), Visual C++ (19.00.23506).

If I replace constructor inheritance with a hand-written version, then GCC starts to compile the code:

struct BaseFooWrapper
{
    BaseFooWrapper(int qux)
    { }
};

struct Foo
{
    Foo(BaseFooWrapper & foo)
        : foo(foo)
    { }

    BaseFooWrapper & foo;
};

struct SomeFooWrapper : public BaseFooWrapper
{
    SomeFooWrapper(int qux)
        : BaseFooWrapper(qux)
    { }


    Foo foo{*this};
};

int main()
{
    SomeFooWrapper wrapped_foo(1);
    return 0;
}

Live on godbolt.com


Obviously it is not very handy, especially when you have many such classes, and leads to boilerplate code. Basically, the very thing that inheriting constructors are designed to fix. This behaviour of GCC renders this great c++11 feature unavailable in such cases.

So I am really curious whether I am doing something illegal with regard to the standard or this is a bug in GCC?


Edit:

Filed a bug report.

Community
  • 1
  • 1
GreenScape
  • 7,191
  • 2
  • 34
  • 64
  • This question is a duplicate of [Inheriting constructors and brace-or-equal initializers](http://stackoverflow.com/questions/32525586/inheriting-constructors-and-brace-or-equal-initializers) (as is [Constructor inheritance and direct member initialisation](http://stackoverflow.com/questions/40932844/constructor-inheritance-and-direct-member-initialisation)) and therefore your bug is a duplicate of the older GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054 – underscore_d May 22 '17 at 08:04
  • Btw, it doesn't "capture this", as it's not a lambda. It just happens to use `*this` as an expression in the brace-or-equal initialiser. I think that's a red herring and the problem would've occurred regardless of whether or not the argument for said initialiser happened to include `this` in it. Did you test for that? – underscore_d May 22 '17 at 08:12
  • @underscore_d, seems that you are correct. Somehow I over-complicated an example. – GreenScape May 22 '17 at 09:31

2 Answers2

6

The problem is not the constructor inheritance, but this line:

Foo foo{*this};

GCC appears to think it will need a default constructor for struct Foo as well, and since the class has a reference, it is not able to do so.

error: no matching function for call to 'Foo::Foo()'
<source>:14:5: note: candidate: Foo::Foo(BaseFooWrapper&)
     Foo(BaseFooWrapper & foo): foo(foo)
     ^~~
<source>:14:5: note:   candidate expects 1 argument, 0 provided
<source>:10:7: note: candidate: constexpr Foo::Foo(const Foo&)

By adding the default constructor it appears to think it needs, then the code compiles:

struct Foo
{

    Foo():foo(*new BaseFooWrapper(0))
    {

    }
    Foo(BaseFooWrapper & foo): foo(foo)
    { 

    }

    BaseFooWrapper & foo;
};

It does look like a bug.

didiz
  • 1,069
  • 13
  • 26
2

I could be wrong, but quoting from the n4527 draft standard in [class.this]:

In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*.

In the OP's code, the initialisation of SomeFooWrapper::foo is not taking place in a member function. Therefore the keyword this has no reasonable meaning as far as the standard is concerned.

Or have I missed something?

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Actually, ititialisation does take place in the member function: `SomeFooWrapper::SomeFooWrapper(int)`. I mean should, according to standard, not in this case, with regard to GCC. – GreenScape May 19 '17 at 07:54