std::max() 和 std::min() 不是 constexpr
我刚刚注意到新标准定义了 min(a,b)
和 max(a,b)
without 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
Any Reason Why those can not be constexpr
?
I just noticed that the new standard defines min(a,b)
and max(a,b)
without constexpr
.
Examples from 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);
Isn't this a pity? I would have liked to write
char data[ max(sizeof(A),sizeof(B)) ];
instead of
char data[ sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B) ];
char data[ MAX(sizeof(A),sizeof(B)) ]; // using a macro
Any reason why those can not be constexpr
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
std::min 和 std::max 在 C++14 中是 constexpr,这显然意味着(现在)没有充分的理由不让它们 constexpr。问题解决了:-)
std::min and std::max are constexpr in C++14, which obviously means there isn't a good reason (these days) not to have them constexpr. Problem solved :-)
重要更新
以下分析是错误的,因为它混淆了一件重要的事情。下面的陈述我确实错过了一个重要的细节,这需要一个完全不同的答案。
这里的问题是函数调用替换此时已经完成。如果调用替代将包括
max
产生的左值到右值的转换,那么一切都会好起来的,因为从引用临时非静态存储持续时间的左值读取是没问题的在计算常量表达式时。但由于读取发生在函数调用替换之外,因此函数调用替换的结果是一个左值。规范的相应文本说但是
max
返回的引用会产生一个左值,该左值指定一个未指定存储持续时间的对象。函数调用替换需要产生一个常量表达式,而不仅仅是一个核心常量表达式。因此max(sizeof(A), sizeof(B))
不保证有效。阅读以下(较旧的)文本时需要考虑上述内容。
目前我看不出您有任何理由不想在那里粘贴
constexpr
。无论如何,下面的代码绝对是有用的,与其他答案所写的相反,我认为这是合法的。并非所有
max
实例化都必须是 constexpr 函数。当前的n3242说如果调用模板,参数推导将产生函数模板特化。调用它将触发函数调用替换。考虑以下调用,
它首先将两个
size_t
纯右值隐式转换为两个引用参数,将两个引用绑定到存储其值的临时对象。对于每个引用临时对象的情况,此转换的结果是一个glvalue(请参阅 4p3)。现在,函数调用替换采用这两个泛左值,并用这些泛左值替换函数体中所有出现的a
和b
。条件将要求对这些泛左值进行左值到右值的转换,这5.19p2 允许
。条件表达式将为第一个或第二个操作数生成一个泛左值。返回的未命名引用 max 将引用该操作数。并且在数组维度大小规范中发生的最终左值到右值的转换将按照上面引用的相同规则有效。
请注意,
initializer_list
目前没有constexpr
成员函数。这是一个已知的限制,将在 C++0x 之后处理,很可能使这些成员成为constexpr
。Critical Update
The below analysis is wrong, because it confuses one important thing. The following statement I did missed one important detail, which requires an entirely different answer.
The problem here is that function invocation substitution is done at that point. If the invocation susbstitution would include the lvalue to rvalue conversion on that glvalue that
max
yields, everything would be fine, because reading from a glvalue that refers to a temporary not of static storage duration is fine during computation of the constant expression. But since the read happens outside of function invocation substitution, the result of function invocation substitution is an lvalue. The respective text of the spec saysBut the reference that
max
returns yields an lvalue that designates an object of unspecified storage duration. Function invocation substitution is required to yield a constant expression, not merely a core constant expression. Somax(sizeof(A), sizeof(B))
is not guaranteed to work.The following (older) text needs to be read taking the above into account.
I can't see any reason at the moment why you wouldn't want to stick a
constexpr
there. Anyway, the following code definitely is usefulContrary to what other answers write, I think this is legal. Not all instantiations of
max
are required to be constexpr functions. The current n3242 saysIf you call the template, argument deduction will yield a function template specialization. Calling it will trigger function invocation substitution. Consider the following call
It will first do an implicit conversion of the two
size_t
prvalues to the two reference parameters, binding both references to temporary objects storing their value. The result of this conversion is a glvalue for each case that refers to a temporary object (see 4p3). Now function invocation substitution takes those two glvalues and substitutes all occurences ofa
andb
in the function body by those glvaluesThe condition will require lvalue to rvalue conversions on these glvalues, which are allowed by 5.19p2
The conditional expression will yield a glvalue to either the first or second operand. The unnamed reference
max
returns will refer to that operand. And the final lvalue to rvalue conversion happening in the array dimension size specification will be valid by the same rule quoted above.Note that
initializer_list
currently doesn't haveconstexpr
member functions. This is a known limitation and will be handled post-C++0x, most likely making those membersconstexpr
.C++14 中包含
std::min()
和std::max()
的constexpr
版本表明,没有基本的制作这些函数(的版本)constexpr
的障碍。当constexpr
添加到 C++11 时,似乎没有足够早地考虑这一点。显然,对于提供比较函数的版本,该函数本身必须是 constexpr 才能成功进行模板扩展。
The inclusion of
constexpr
versions ofstd::min()
andstd::max()
in C++14 demonstrates that there's no fundamental obstacle to making (versions of) these functionsconstexpr
. It seems that this wasn't considered early enough whenconstexpr
was added to C++11.Obviously, for the versions where a comparison function is provided, that function must itself be
constexpr
for the template expansion to succeed.如果您使用常量表达式作为参数调用它们,则
min
和max
仅是常量表达式。由于它们的用途比这更普遍,因此您无法做出声明。以下是 维基百科关于
constexpr
的说法(强调额外)。我知道维基百科不是最终的参考,但我相信在这种情况下它是正确的。min
andmax
are only constant expressions if you call them with constant expressions as arguments. Since they're meant to be much more generally usable than that, you can't make the declaration.Here's what Wikipedia says about
constexpr
(emphasis added). I know Wikipedia is not the ultimate reference, but I believe it's correct in this case.我的猜测是,在一般情况下,operator<(T, T) 也不能保证是 constexpr。
My guess is that, in the general case, operator<(T, T) is not guaranteed to be constexpr either.