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.问题解决了 :-)
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_t
prvalues 隐式转换为两个引用参数,将两个引用绑定到存储其值的临时对象.这种转换的结果是每个引用临时对象的情况的glvalue(见4p3).现在函数调用取代反应这两个glvalues并替换出现的所有a
和b
这些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
.