std::max() and std::min() not constexpr

std::max() and std::min() not constexpr

本文关键字:std constexpr not min and max      更新时间:2023-10-16

我刚刚注意到新标准定义了min(a,b)max(a,b) ,没有 constexpr

取自25.4.7,[g.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 ?

std::min和std::max在c++ 14中是constexpr,这显然意味着(现在)没有理由不使用它们。问题解决:-)

紧急更新

下面的分析是错误的,因为它混淆了一件重要的事情。下面我所做的陈述漏掉了一个重要的细节,这需要一个完全不同的答案。

max返回的未命名引用将指向该操作数。

这里的问题是函数调用替换在此时已完成。如果调用替换将包括max产生的glvalue的左值到右值转换,那么一切都会很好,因为在计算常量表达式期间,从引用静态存储持续时间的临时变量的glvalue中读取是很好的。但是由于读取发生在函数调用替换之外,所以函数调用替换的结果是左值。规范的相应文本显示

引用常量表达式是一个左值核心常量表达式,用于指定具有静态存储时间的对象或函数。

但是max返回的引用产生一个左值,该左值指定了一个未指定存储持续时间的对象。函数调用替换需要产生常量表达式,而不仅仅是核心常量表达式。所以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)。函数调用替换用这两个glvalue替换函数体中出现的所有ab

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

条件将要求在这些左值上进行左值到右值的转换,这是5.19p2

所允许的
  • 一个文字类型的全局值,它引用一个用常量表达式
  • 初始化的非易失性临时对象

条件表达式将生成第一个或第二个操作数的全局值。未命名的引用max返回指向该操作数。数组尺寸大小规范中发生的最后的左值到右值转换将根据上面引用的相同规则有效。


注意initializer_list目前没有constexpr成员函数。这是一个已知的限制,将在c++ 0x之后处理,最有可能使这些成员成为constexpr .

在c++ 14中包含std::min()std::max()constexpr版本表明没有根本的障碍使这些函数(版本)成为constexpr。当constexpr被添加到c++ 11中时,似乎没有足够早地考虑到这一点。

显然,对于提供了比较函数的版本,该函数本身必须是constexpr才能使模板展开成功。

minmax只有在使用常量表达式作为参数调用时才是常量表达式。因为它们的目的是更普遍地可用,所以你不能做声明。

这是维基百科对constexpr的解释。我知道维基百科不是最终的参考,但我相信它在这种情况下是正确的。

constexpr在函数上的使用对…施加了非常严格的限制这个函数能做什么。首先,函数必须有非空返回值类型。二是功能内容格式必须为:return expr。第三,expr必须是常量表达式,在论证之后替换。这个常数表达式可以只调用其他定义的函数吗作为constexpr,也可以使用other

我的猜测是,在一般情况下,操作符<(T, T)也不能保证是constexpr