37

我刚刚注意到新标准定义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什么理由?

4

5 回答 5

21

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

于 2016-03-05T12:59:48.310 回答
13

关键更新

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

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

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

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

但是max返回的引用会产生一个左值,该左值指定一个未指定存储持续时间的对象。需要函数调用替换来产生一个常量表达式,而不仅仅是一个核心常量表达式。所以max(sizeof(A), sizeof(B))不能保证工作。

考虑到上述内容,需要阅读以下(较旧的)文本


目前我看不出有什么理由让你不想把 a 放在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两个引用参数,将两个引用绑定到存储其值的临时对象。此转换的结果是每个引用临时对象的情况的泛左值(参见 4p3)现在函数调用替换采用这两个glvalues并用这些glvalues替换a函数b体中的所有出现

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

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

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

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


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

于 2011-04-10T15:01:49.857 回答
1

在 C++14 中包含 和 的版本constexpr表明,制作这些函数的(版本)没有根本障碍。似乎在添加到 C++11时还不够早地考虑到这一点。std::min()std::max()constexprconstexpr

显然,对于提供比较函数的版本,该函数本身必须constexpr是模板扩展成功的原因。

于 2016-07-14T08:11:22.067 回答
-1

min并且max仅当您使用常量表达式作为参数调用它们时才是常量表达式。由于它们的用途比这更普遍,因此您不能做出声明。

这是维基百科所说的constexpr(强调添加)。我知道维基百科不是最终的参考,但我相信在这种情况下它是正确的。

函数上的使用constexpr对该函数可以做什么施加了非常严格的限制。首先,函数必须具有非 void 返回类型。二、函数内容必须为:return expr。 第三,在参数替换之后, expr 必须是一个常量表达式。此常量表达式可能只调用定义为 constexpr 的其他函数,也可能使用其他常量表达式数据变量。

于 2011-04-09T14:33:11.647 回答
-3

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

于 2011-04-09T13:01:55.423 回答