我刚刚注意到新标准定义了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
?
答案 0 :(得分:13)
以下分析是错误的,因为它混淆了一件重要的事情。以下陈述我错过了一个重要的细节,这需要一个完全不同的答案。
未命名的引用
max
返回将引用该操作数。
这里的问题是函数调用替换在那时完成。如果调用susbstitution将包括max
产生的glvalue上的左值转换的左值,那么一切都会没问题,因为从glvalue中读取一个临时的非静态存储持续时间是很好的常量表达式。但由于读取发生在函数调用替换之外,因此函数调用替换的结果是 lvalue 。规范的相应文本说
引用常量表达式是一个左值核心常量表达式,用于指定具有静态存储持续时间或函数的对象。
但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
prvalues隐式转换为两个引用参数,将两个引用绑定到存储其值的临时对象。对于引用临时对象的每种情况,此转换的结果是 glvalue (请参阅4p3)。现在,函数调用替换采用这两个glvalues,并用函数体中的a
和b
替换所有glvalues
return (<glval.a>) > (<glval.b>) ? (<glval.a>) : (<glval.b>);
这个条件需要左值来对这些glvalues进行rvalue转换,这是5.19p2允许的
- 一个文字类型的glvalue,它引用一个用常量表达式初始化的非易失性临时对象
条件表达式将为第一个或第二个操作数产生一个glvalue。未命名的引用max
返回将引用该操作数。并且在数组维度大小规范中发生的rvalue转换的最终左值将通过上面引用的相同规则有效。
请注意,initializer_list
目前没有constexpr
个成员函数。这是一个已知的限制,将在C ++ 0x之后处理,最有可能使这些成员constexpr
。
答案 1 :(得分:13)
std :: min和std :: max are constexpr,这显然意味着没有充分的理由(这些天)没有他们的constexpr。问题解决了: - )
答案 2 :(得分:1)
在C ++ 14中包含constexpr
版本的std::min()
和std::max()
表明,制作(版本)这些函数{{1}没有根本障碍}}。当constexpr
被添加到C ++ 11时,似乎没有考虑到这一点。
显然,对于提供比较功能的版本,该功能本身必须为constexpr
才能使模板扩展成功。
答案 3 :(得分:-1)
min
和max
只是常量表达式。由于它们通常比这更有用,所以你不能发表声明。
这是Wikipedia says about constexpr
(强调添加)。我知道维基百科不是最终的参考,但我认为在这种情况下它是正确的。
在函数上使用
constexpr
对...施加非常严格的限制 该功能可以做什么。首先, 函数必须具有非void返回 类型。二,功能内容 必须是以下形式:return expr。 第三,expr必须是常数 论证后的表达 代换。这种不断表达 可能只调用其他定义的函数 作为constexpr,或者它可能使用其他 常量表达式数据变量。
答案 4 :(得分:-3)
我的猜测是,在一般情况下,运算符&lt;(T,T)也不保证是constexpr。