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