std :: max () и std :: min () не constexpr - PullRequest
       44

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

33 голосов
/ 09 апреля 2011

Я только что заметил, что новый стандарт определяет 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 ]

14 голосов
/ 05 марта 2016

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

13 голосов
/ 10 апреля 2011

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

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

Неименованная ссылка max возвращает ссылку на этот операнд.

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

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

Но ссылка, которую возвращает max, возвращает lvalue, который обозначает объект неопределенной продолжительности хранения.Подстановка вызова функции необходима для получения константного выражения , а не просто core константного выражения.Таким образом, 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 в два ссылочных параметра, привязав обе ссылки к временным объектам, хранящим их значение.Результатом этого преобразования является glvalue для каждого случая, который ссылается на временный объект (см. 4p3).Теперь подстановка вызова функции принимает эти два glvalues ​​и заменяет все вхождения a и b в теле функции на эти glvalues ​​

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

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

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

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


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

1 голос
/ 14 июля 2016

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

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

0 голосов
/ 09 апреля 2011

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

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

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

0 голосов
/ 09 апреля 2011

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

...