我们应该尽可能使用 constexpr 吗?

Posted

技术标签:

【中文标题】我们应该尽可能使用 constexpr 吗?【英文标题】:Should we use constexpr everywhere we can? 【发布时间】:2011-07-22 03:19:58 【问题描述】:

我们显然无法做到所有constexpr。如果我们不做任何事情constexpr,那么不会有任何大问题。到目前为止,已经编写了很多没有它的代码。

但是在任何可能拥有它的东西上打constexpr 是个好主意吗?这有什么潜在的问题吗?

【问题讨论】:

【参考方案1】:

它不会打扰编译器。当/如果您在不符合constexpr 要求的代码上使用它时,编译器将(或无论如何应该)为您提供诊断。

同时,我会有点犹豫,因为你可以。尽管它不会/不会打扰编译器,但您的主要受众是阅读代码的其他。至少在 IMO,你应该使用 constexpr 来向他们传达一个相当具体的含义,并且只是将它打在其他表达上,因为你会误导。我认为读者应该想知道标记为 constexpr 但仅用作正常运行时函数的函数发生了什么。

同时,如果您确实希望在编译时使用一个函数,而您还没有以这种方式使用它,则标记constexpr 可能更有意义。

【讨论】:

等等,这是编译器可以为自己派生的属性吗?那为什么还有关键字呢? @Nemo 当您错误地声明了不满足所有要求的 constexpr 时,编译器需要发出诊断。因此,关键字至少对于作者积极断言声明的函数或构造函数满足这些要求很有用。我让另一个问题打开(如果编译器可以处理它,则隐式允许未标记为 constexpr 的东西在常量上下文中)。 @Luc:所以它只是一个编译时断言?似乎他们可以在不窃取整个关键字的情况下实现这一点。不过没关系。 @Nemo 就像要求数组的大小是一个常量表达式一样。编译器可以“弄清楚”int i = 1; char array[i];,但我们不允许这样做。 (实际上是一个糟糕的例子,因为const int i = expr; 完全代表了您所建议的数组声明仅在某些情况下是正确的;) 是的,这是编译器可以为自己派生的东西。我似乎记得一些讨论建议它应该,但目前找不到它。无论如何,这并没有成为标准,所以这并不重要。【参考方案2】:

为什么我不费心尝试将constexpr 以列表形式出现在每个机会中,并且没有特定的顺序:

我不经常编写单行函数 当我编写单行代码时,它通常会委托给非 constexpr 函数(例如,std::get 最近出现了好几次) 它们操作的类型并不总是字面量类型;是的,引用是文字类型,但如果引用的类型本身不是文字本身,我在编译时实际上不能有任何实例 它们返回的类型并不总是字面的 就其语义而言,它们在编译时并非全部有用,甚至没有意义 我喜欢将实现与声明分开

Consexpr 函数有很多限制,以至于它们只能用于特殊用途。通常不是优化,也不是理想的功能超集。当我确实写一个时,通常是因为单独的元函数或常规函数不会削减它,而且我对它有一种特殊的心态。 constexpr 函数不像其他函数味道

我对 constexpr 构造函数没有特别的意见或建议,因为我不确定我是否能完全理解它们,而且用户定义的文字尚不可用。

【讨论】:

【参考方案3】:

是的。我相信尽可能地使用constness 总是一个好习惯。例如,在您的 class 中,如果给定的方法没有修改任何成员,那么您总是倾向于在最后放置一个 const 关键字。

除了语言方面,提到constness 也很好地表明了未来的程序员/审阅者该表达式在该区域内具有 const-ness。它与良好的编码实践有关,也增加了可读性。例如(来自@Luc)

constexpr int& f(int& i)  return get(i); 

现在输入constexpr 表明get() 也必须是constexpr

我认为constexpr 没有任何问题或暗示。

编辑constexpr 的另一个优点是您可以在某些情况下将它们用作template 参数。

【讨论】:

constexpr 在应用于函数时与不变性完全正交,请考虑:constexpr int& f(int& i) return i; ,将其用作++f(some_int) 非常好。 constexpr int i; 然而确实是不可变的。【参考方案4】:

我倾向于同意 Scott Meyers 的观​​点(就大多数事情而言):“尽可能使用 constexpr”(来自 Effective Modern C++ 的第 15 条),尤其是在您提供API 供其他人使用。如果您希望使用函数执行编译时初始化,但由于库没有声明它constexpr 而不能这样做,这可能真的很令人失望。此外,所有类和函数都是 API 的一部分,无论是被全世界使用还是只是您的团队使用。因此,尽可能使用它,以扩大其使用范围。

// Free cup of coffee to the API author, for using constexpr
// on Rect3 ctor, Point3 ctor, and Point3::operator*
constexpr Rect3 IdealSensorBounds = Rect3(Point3::Zero, MaxSensorRange * 0.8);

也就是说,constexpr 是接口的一部分,所以如果接口不能自然地适合可以是constexpr 的东西,请不要提交它,以免以后必须破坏 API。也就是说,不要仅仅因为当前的,只有实现可以处理它而将constexpr 提交给接口。

【讨论】:

以上是关于我们应该尽可能使用 constexpr 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Constexpr变量不是编译时间值吗?

constexpr 替换数学常量,如 M_PI

我们如何理解关于 constexpr 的“如果可能”

解读C++ constexpr关键字的特性

当值是非常量但使用常量表达式初始化时使用 constexpr?

constexpr