std :: max()和std :: min()不是constexpr

tow*_*owi 34 c++ max min constexpr c++11

我刚刚注意到新标准的定义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);
Run Code Online (Sandbox Code Playgroud)

这不是很可惜吗?我本来想写的

char data[ max(sizeof(A),sizeof(B)) ];
Run Code Online (Sandbox Code Playgroud)

代替

char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ];
char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro
Run Code Online (Sandbox Code Playgroud)

那些不可能的constexpr原因什么?

ein*_*ica 15

std :: min和std :: max C++ 14 中的constexpr,这显然意味着没有充分的理由(这些天)没有他们的constexpr.问题解决了 :-)

  • 这应该是我认为的评论 (5认同)

Joh*_*itb 13

关键更新

以下分析是错误的,因为它混淆了一件重要的事情.以下陈述我错过了一个重要的细节,这需要一个完全不同的答案.

未命名的引用max返回将引用该操作数.

这里的问题是,函数调用替换在这一点上.如果调用susbstitution将包括对产生的glvalue的右值转换的左值max,则一切都会没问题,因为在计算常量表达式期间从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;
}
Run Code Online (Sandbox Code Playgroud)

与其他答案相反,我认为这是合法的.并非所有实例max都需要constexpr函数.目前的n3242说

如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足constexpr函数或constexpr构造函数的要求,则该特化不是constexpr函数或constexpr构造函数.

如果调用模板,则参数推导将产生函数模板特化.调用它将触发函数调用替换.考虑以下电话

int a[max(sizeof(A), sizeof(B))];
Run Code Online (Sandbox Code Playgroud)

它将首先将两个size_tprvalues 隐式转换为两个引用参数,将两个引用绑定到存储其值的临时对象.这种转换的结果是每个引用临时对象的情况的glvalue(见4p3).现在函数调用取代反应这两个glvalues并替换出现的所有ab这些glvalues函数体中

return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);
Run Code Online (Sandbox Code Playgroud)

该条件将需要左值来对这些glvalues进行rvalue转换,这是5.19p2允许的

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

条件表达式将向第一个或第二个操作数产生glvalue.未命名的引用max返回将引用该操作数.并且在数组维度大小规范中发生的rvalue转换的最终左值将通过上面引用的相同规则有效.


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

  • C++委员会建议,函数调用替换可能会产生一个引用临时值的左值.g ++表现得那样,但clang目前实现了所写的标准. (2认同)