Вызов функции-члена constexpr через ссылку - clang vs gcc - PullRequest
8 голосов
/ 28 февраля 2020

Рассмотрим следующий пример ( snippet (0) ):

struct X
{
    constexpr int get() const { return 0; }
};

void foo(const X& x)
{
    constexpr int i = x.get();
}

int main()
{
    foo(X{});
}

Приведенный выше пример компилируется со всеми версиями g++ до g++ 10.x и никогда не компилируется в clang++. Сообщение об ошибке:

error: 'x' is not a constant expression
    8 |     constexpr int i = x.get();
      |

живой пример на godbolt.org

Ошибка имеет смысл , поскольку x никогда не является константным выражением в теле foo, однако:

  • X::get() помечено constexpr и не зависит от состояния x;

  • При изменении const X& на const X код компилируется с каждым компилятором (на godbolt.org) фрагмент (1) .


Это становится еще интереснее, когда я отмечаю X::get() как static ( (на кресте). org) фрагмент (2) ). С этим изменением все протестированные версии g++ (включая транк) компилируются, в то время как clang++ по-прежнему не всегда компилируется.

Итак, мои вопросы:

  • Правильно ли g++ 9.x принять фрагмент (0) ?

  • Правильно ли все компиляторы принимают фрагмент (1) ? Если да, то почему ссылка значима?

  • Правильны ли g++ 9.x и g++ trunk при принятии фрагмента (2) ?

1 Ответ

12 голосов
/ 28 февраля 2020

Правильно ли g ++ 9.x при приеме фрагмента (0)?

Нет.

Все ли компиляторы верны в принятии фрагмента (1)? Если да, то почему эта ссылка значима?

Да, это так.

В константном выражении нельзя использовать id-выражение, обозначающее ссылку, у которой нет предыдущего константного выражения. инициализация или начало его жизни во время оценки постоянного выражения. [expr.const] /2.11 ( то же самое в C ++ 20 )

То же самое не верно, если вы называете переменную без ссылки без какого-либо участия Преобразование lvalue в rvalue. x.get() относится только к x как lvalue и вызывает только функцию constexpr, которая на самом деле не имеет доступа ни к одному из элементов x, поэтому проблем нет.

Являются g ++ 9 .x и ствол g ++ верны в принятии фрагмента (2)?

Нет, поскольку выражение все еще содержит подвыражение x, которое нарушает указанное выше правило.

...