MSVC здесь неверен, давайте начнем с упрощенной версии кода:
struct N {
static constexpr size_t v = 0;
};
constexpr
bool operator<(N n1, size_t n2) {
return n1.v < n2;
}
void foo(N v) {
static_assert(v < 5, ""); // C++11 does not allow terse form
}
Сначала мы рассмотрим static_assert
, нарушили ли мы какие-либо правила для константных выражений?Если мы посмотрим на [expr.const] p2.2 :
вызов функции, отличной от конструктора constexpr для литерального класса или функции constexpr [Примечание: перегрузкаразрешение (13.3) применяется как обычно - конец примечания];
Все хорошо, operator<
- функция constexpr, а конструктор копирования для N
- конструктор constexpr для литерального класса.
Перейдем к operator<
и рассмотрим сравнение n1.v < n2
, и если мы посмотрим на [expr.const] p2.9 :
lvalue to-Преобразование в значение (4.1), если только оно не применяется к
- glvalue целочисленного типа или типа перечисления, которое относится к энергонезависимому объекту const с предшествующей инициализацией, инициализированным с помощью константного выражения, или
- glvalue литералатип, который ссылается на энергонезависимый объект, определенный с помощью constexpr, или ссылающийся на подобъект такого объекта, или
- glvalue литерального типа, который ссылается на энергонезависимый временный объект, время жизни которого не закончилосьИнициализируется с помощью константного выражения
Здесь мы тоже хороши.В исходном примере мы ссылаемся на шаблонный типовой аргумент, который можно использовать в константном выражении, поэтому те же рассуждения применимы и к этому случаю.Оба операнда <
являются пригодными для использования константными выражениями.
Мы также можем видеть, что MSVC по-прежнему рассматривает упрощенный случай как неправильно сформированный , даже если clang и gcc принимают его.