инициализация члена структуры constexpr - PullRequest
0 голосов
/ 13 февраля 2019

Этот код компилируется:

struct Info
{
    constexpr Info(bool val) : counted(false), value(unsigned(val)) {}
    constexpr Info(unsigned val) : counted(true), value(val) {}

    bool counted;
    unsigned value;
};

constexpr const auto data = std::array{
    Info{true}, Info{42u}
};

struct Foo
{
    constexpr static inline const auto data = std::array{
        Info{true}, Info{42u}
    };
};

Этот код не:

struct Foo
{
    struct Info
    {
        constexpr Info(bool val) : counted(false), value(unsigned(val)) {}
        constexpr Info(unsigned val) : counted(true), value(val) {}

        bool counted;
        unsigned value;
    };

    constexpr static inline const auto data = std::array{
        Info{true}, Info{42u}
    };
};

Сообщаемая ошибка (в MSVC, gcc и clang) предполагает, что они думают, что InfoКонструктор не определен или не constexpr, например.из clang:

prog.cc:21:5: note: undefined constructor 'Info' cannot be used in a constant expression
    Info{true}, Info{42u}
    ^

Почему?

(Возможно, относится к этот вопрос , но Info должен быть завершен на момент использования; только Fooвсе еще не завершен.)

1 Ответ

0 голосов
/ 13 февраля 2019

Сообщение об ошибке gcc-8, возможно, более ясно:

   constexpr Foo::Info::Info(bool)’ called in a constant expression before 
   its definition is complete

Кажется, ошибка генерируется в соответствии с [expr.const] §2:

Выражение e является выражением основной константы , если только оценка e, следуя правилам абстрактной машины (4.6), не будет оценивать одно из следующих выражений:

...

(2.3) - вызов неопределенной функции constexpr или неопределенного конструктора constexpr;

Почему это не определено, когда вызов явно после определения?

Дело в том, что определения функций-членов откладываются до закрывающей скобки самого внешнего включающего класса (потому что они могут видеть членов включающих классов),Рассмотрим определение этого класса:

constexpr int one = 1;

struct Foo
{
    struct Bar
    {
        static constexpr int get_one() { return one; }
    };

    static constexpr int two = Bar::get_one() + 1;
    static constexpr int one = 42;
};

Предполагая, что это должно работать, как реализация может обработать это определение?

one внутри Bar::get_one относится к Foo::one, а не ::one, поэтому он должен быть обработан после того, как этот член увиден.Он используется в определении two, который является constexpr, поэтому он должен быть обработан перед инициализатором этого члена.Таким образом, чтобы это работало, общий порядок должен быть one, затем get_one, затем two.

Но реализация C ++ не работает таким образом.Они не делают сложного анализа зависимостей.Они обрабатывают объявления и определения в порядке их просмотра, за некоторыми исключениями, перечисленными в [class.mem] §2.

Кажется, я не могу найти в стандарте явного упоминания о том, что функция-член constexpr считается неопределенной до тех пор, пока не будет завершен самый охватывающий класс, но это единственная логическая возможность.Это не может работать по-другому.

...