Сообщение об ошибке 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 считается неопределенной до тех пор, пока не будет завершен самый охватывающий класс, но это единственная логическая возможность.Это не может работать по-другому.