Использование статической функции-члена Constexpr
Рассмотрим следующий пример кода:
#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()
код, чтобы он не DoIt()
в шаблонную 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
Похоже, ошибка для меня.
Тип и значение выражения h.size()
определяется [expr.ref]
"Доступ к члену класса":
Аббревиатура postfix-expression.id-expression как E1.E2
, E1
называется выражением объекта. [...]
а также
Если E2
является (возможно, перегруженной) функцией-членом, разрешение перегрузки функции используется для определения того, относится ли E1.E2
к статической или нестатической функции-члену.
- (6.3.1) Если это относится к статической функции-члену, а тип
E2
является "функцией списка параметров-типа, возвращающего T
", то E1.E2
является lvalue; выражение обозначает статическую функцию-член. Тип E1.E2
аналогичен типу E2
, а именно "функция списка параметров-типа, возвращающего T
".
Это означает, что h.size
имеет тот же тип, что и ::MyClass::size
и оценивается как таковой, независимо от того, является constexpr
h
constexpr
или нет.
h.size()
является вызовом функции constexpr
и является выражением основной константы в соответствии с [expr.const]/4
.