Static_cast указателя-члена в контексте constexpr на g++
Я столкнулся с проблемой с g++ с повышением уровня указателя-члена в контексте constexpr с использованием static_cast. См. Пример кода.
При компиляции с g++ версии 6.3 и 7.0 они дают ошибку компиляции, говоря, что reinterpret_cast не является постоянным выражением.
Хотя версия clang 4.0 не дает ошибок, которые, я думаю, верны, поскольку здесь нет reinterpret_cast.
Это ошибка в g++ или clang? Какое правильное поведение?
struct Base {};
struct Derived : Base
{
int i;
};
struct Ptr
{
constexpr Ptr(int Derived::* p) : p(static_cast<int Base::*>(p)){}
int Base::* p;
};
constexpr Ptr constexpr_ptr(&Derived::i);
Выход компилятора
g++ -c -std=c++14 test.cpp
test.cpp:17:40: in constexpr expansion of ‘Ptr(&Derived::i)’
test.cpp:11:41: error: a reinterpret_cast is not a constant expression
constexpr Ptr(int Derived::* p) : p(static_cast<int Base::*>(p)){}
^~~~~~~~~~~~~~~~~~~~~~~~~~~
Ответы
Ответ 1
GCC предположительно неправильно описывает [expr.static.cast]/12, что позволяет делать ваши броски и примечания, что
Если класс B
содержит исходный элемент или является базовым или производным классом класса, содержащего исходный элемент, результирующий указатель на член указывает на исходный элемент. В противном случае поведение undefined.
Так как Base
действительно является базой класса, содержащего элемент, поведение должно быть определено, а конструктор вызывает константное выражение.