std::max() и std::min() не constexpr

Я просто заметил, что новый стандарт определяет min(a,b) а также max(a,b) без constexpr,

Примеры из 25.4.7, [alg.min.max]:

template<class T> const T& min(const T& a, const T& b);
template<class T> T min(initializer_list<T> t);

Разве это не жаль? Я бы хотел написать

char data[ max(sizeof(A),sizeof(B)) ];

вместо

char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ];
char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro

Любая причина, почему те не могут бытьconstexpr?

5 ответов

Решение

Критическое обновление

Приведенный ниже анализ неверен, потому что он путает одну важную вещь. В следующем утверждении я пропустил одну важную деталь, которая требует совершенно другого ответа.

Безымянная ссылка max возврат будет ссылаться на этот операнд.

Проблема здесь в том, что подстановка вызова функции выполняется в этот момент. Если в вызове susbstitution будет включено преобразование lvalue в rvalue для этого glvalue, max да, все будет хорошо, потому что чтение из glvalue, которое ссылается на временную не статическую длительность хранения, прекрасно при вычислении константного выражения. Но поскольку чтение происходит вне подстановки вызова функции, результатом подстановки вызова функции является lvalue. Соответствующий текст спецификации говорит

Выражение ссылочной константы - это выражение основной константы lvalue, которое обозначает объект со статической продолжительностью хранения или функцию.

Но ссылка что max Возвращает возвращает значение l, которое обозначает объект с неопределенным сроком хранения. Подстановка вызова функции необходима для получения константного выражения, а не просто выражения основной константы. Так max(sizeof(A), sizeof(B)) не гарантируется работа.

Следующий (более старый) текст необходимо прочитать с учетом вышесказанного.


Я не вижу никакой причины в данный момент, почему вы не хотели бы вставлять constexpr там. Во всяком случае, следующий код определенно полезен

template<typename T> constexpr
T const& max(T const& a, T const& b) {
  return a > b ? a : b;
}

Вопреки тому, что пишут другие ответы, я думаю, что это законно. Не все экземпляры max должны быть функциями constexpr. Текущий n3242 говорит

Если конкретизированная шаблонная специализация шаблона функции constexpr или функции-члена шаблона класса не сможет удовлетворить требования к функции constexpr или конструктору constexpr, эта специализация не является функцией constexpr или конструктором constexpr.

Если вы вызываете шаблон, вывод аргумента приведет к специализации шаблона функции. Вызов этого вызовет замену вызова функции. Рассмотрим следующий звонок

int a[max(sizeof(A), sizeof(B))];

Сначала будет выполнено неявное преобразование двух size_t prvalues ​​к двум ссылочным параметрам, привязывая обе ссылки к временным объектам, хранящим их значение. Результатом этого преобразования является glvalue для каждого случая, который ссылается на временный объект (см. 4p3). Теперь подстановка вызова функции принимает эти два значения и заменяет все вхождения a а также b в теле функции этими блестками

return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);

Условие потребует от lvalue преобразовать значения в этих glvalues, которые разрешены в 5.19p2

  • glvalue литерального типа, который относится к энергонезависимому временному объекту, инициализированному с постоянным выражением

Условное выражение будет давать glvalue для первого или второго операнда. Безымянная ссылка max возврат будет ссылаться на этот операнд. И окончательное преобразование lvalue в rvalue, происходящее в спецификации размера измерения массива, будет действительным по тому же правилу, указанному выше.


Обратите внимание, что initializer_list в настоящее время не имеет constexpr функции-члены. Это известное ограничение, и оно будет обработано после C++0x, скорее всего, с этими членами constexpr,

std::min и std::max являются constexpr в C++14, что, очевидно, означает, что нет веской причины (в наши дни) не использовать их constexpr. Задача решена:-)

Включение constexpr версии std::min() а также std::max() в C++14 демонстрирует, что нет никаких фундаментальных препятствий для создания (версий) этих функций constexpr, Кажется, что это не считалось достаточно рано, когда constexpr был добавлен в C++11.

Очевидно, что для версий, где предусмотрена функция сравнения, сама эта функция должна быть constexpr для расширения шаблона, чтобы преуспеть.

min а также max являются только константными выражениями, если вы вызываете их с константными выражениями в качестве аргументов. Так как они предназначены для более общего использования, вы не можете сделать заявление.

Вот что говорит Википедия constexpr(выделение добавлено). Я знаю, что Википедия не является окончательной ссылкой, но я считаю, что это правильно в этом случае.

Использование constexpr на функцию накладывает очень строгие ограничения на то, что эта функция может делать. Во-первых, функция должна иметь тип возврата не void. Во-вторых, содержимое функции должно иметь вид: return expr. В-третьих, expr должен быть константным выражением после подстановки аргумента. Это константное выражение может вызывать только другие функции, определенные как constexpr, или может использовать другие переменные данных константного выражения.

Я предполагаю, что в общем случае оператор<(T, T) также не обязательно будет constexpr.

Другие вопросы по тегам