Использование статической функции-члена Constexpr - PullRequest
0 голосов
/ 12 февраля 2019

Рассмотрим следующий пример кода:

#include <array>

struct MyClass
{
  size_t value = 0;

  constexpr static size_t size() noexcept
  {
    return 3;
  }
};

template <size_t N>
void DoIt()
{
  MyClass h;
  std::array<int, h.size()> arr;
}

int main()
{
  DoIt<1>();
}

Когда я пытаюсь скомпилировать это с GCC 7.3.0, я получаю ошибку о том, что h нельзя использовать в контексте non-constexpr:

cexpr.cpp: In function ‘void DoIt()’:
cexpr.cpp:17:26: error: the value of ‘h’ is not usable in a constant expression
   std::array<int, h.size()> arr;
                          ^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
   MyClass h;
           ^
cexpr.cpp:17:27: error: the value of ‘h’ is not usable in a constant expression
   std::array<int, h.size()> arr;
                           ^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
   MyClass h;
           ^

Однако, когда я пытаюсь скомпилировать точно такой же код в Clang 6.0.0, он компилируется без каких-либо ошибок.Кроме того, когда я изменяю код, чтобы он не входил в шаблонную функцию DoIt(), GCC компилирует это очень хорошо:

#include <array>

struct MyClass
{
  size_t value = 0;

  constexpr static size_t size() noexcept
  {
    return 3;
  }
};

int main()
{
  MyClass h;
  // this compiles just fine in Clang and GCC
  std::array<int, h.size()> arr;
}

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

1 Ответ

0 голосов
/ 08 марта 2019

Мне кажется, что это ошибка.

Тип и значение выражения h.size() определяется [expr.ref] "Доступ к члену класса":

[expr.post]/3

Сокращение postfix-expression.id-expression как E1.E2, E1 называется выражением объекта.[...]

и

[expr.post]/6.3.1

Если E2 является (возможно, перегруженным) членомфункция, разрешение перегрузки функции используется для определения, относится ли E1.E2 к статической или нестатической функции-члену.

  • (6.3.1) Если это относится к статической функции-члену и типуE2 - это «функция списка параметров, возвращающая T», тогда E1.E2 - это lvalue; выражение обозначает статическую функцию-член .Тип E1.E2 совпадает с типом E2, а именно «функция списка параметров, возвращающего T».

Это означает, что h.size имееттот же тип, что и ::MyClass::size и оценивается как таковой, независимо от того, что h равно constexpr или нет .

h.size() является вызовом constexpr функция и является основным константным выражением в соответствии с [expr.const]/4.

...