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