Все версии GCC борются с инициализатором элемента по умолчанию, который фиксирует это, в сочетании с унаследованными конструкторами

Эта история похожа на предыдущий вопрос. Все версии GCC, поддерживающие С++ 11, имеют такое точное поведение. Я не мог найти другого компилятора, который борется со своим тестовым случаем.

Тестовый пример:

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


Этот фрагмент кода компилируется с clang (с 3.4 по 4.0), icc (16, 17), Visual С++ (19.00.23506).).

Если я заменил наследование конструктора рукописной версией, то GCC начнет компилировать код:

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


Очевидно, что это не очень удобно, особенно когда у вас много таких классов и приводит к шаблону. В принципе, то, что наследует конструкторы, предназначено для исправления. Такое поведение GCC делает эту замечательную функцию С++ 11 недоступной в таких случаях.

Итак, мне действительно интересно, что я делаю что-то незаконное в отношении стандарта, или это ошибка в GCC?


Edit:

Подано сообщение об ошибке .

Ответ 1

Проблема заключается не в наследовании конструктора, а в этой строке:

Foo foo{*this};

Кажется, что GCC считает, что для конструктора Foo также понадобится конструктор по умолчанию, и поскольку класс имеет ссылку, он не может этого сделать.

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&)

Добавив конструктор по умолчанию, кажется, он считает, что это необходимо, тогда код компилируется:

struct Foo
{

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

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

    }

    BaseFooWrapper & foo;
};

Это похоже на ошибку.

Ответ 2

Я могу ошибаться, но цитирую из стандарта проекта n4527 в [class.this]:

В теле нестатической (9.3) функции-члена ключевым словом является выражение prvalue, значение которого это адрес объекта, для которого вызывается функция. Тип этого в членной функции класс X является X *.

В OP-коде инициализация SomeFooWrapper::foo не выполняется в функции-члене. Поэтому ключевое слово this не имеет разумного смысла в отношении стандарта.

Или я что-то пропустил?