【发布时间】:2011-05-16 11:35:42
【问题描述】:
我一直在研究 C++ 的 constexpr 新特性,但我并不完全了解它的必要性。
例如下面的代码:
constexpr int MaxSize()
{
...
return ...;
}
void foo()
{
int vec[MaxSize()];
}
可以替换为:
int MaxSize()
{
...
return ...;
}
static const int s_maxSize = MaxSize();
foo()
{
int vec[s_maxSize];
}
更新
第二个示例实际上不是标准的 ISO C++(感谢一些用户指出这一点),但某些编译器(例如 gcc)支持它。因此,使程序有效的不是const,而是 gcc 支持这种非标准特性的事实。 (据我所知,这仅在数组被定义为函数或方法的本地时才有可能,因为在编译时仍必须知道全局数组的大小。)如果我在没有选项 -std=c++98 -pedantic-errors 的情况下进行编译,即使代码
int MaxSize()
{
return 10;
}
void foo()
{
int vec[MaxSize()];
}
将使用 gcc 编译。
因此,我将尝试重新表述我的问题,同时考虑到目前收到的反馈(以及我在此期间完成的一些进一步阅读)。
我大量使用const 关键字。使用const,我可以定义一个在其整个生命周期内具有特定值的常量。可以使用任何表达式初始化常量,该表达式只计算一次,即在创建常量时。对于这些情况,我认为constexpr 毫无用处:它会引入一个非常小的优化,因为定义常量值的表达式将在编译时而不是运行时计算。每次我需要一个带有复杂初始化的运行时常量时,我都会使用关键字const。
所以constexpr 在我们需要在编译时初始化一个常量的情况下可能会派上用场。一个例子是向量定义:标准不支持在运行时定义大小。另一个例子是带有一个或多个非类型参数的模板。
在这种情况下,我通常使用宏:
#define MAX_SIZE (10)
void foo()
{
int vec[MAX_SIZE];
}
但是,如果我理解正确的话,constexpr 函数比宏更强大,因为它们允许在其定义中递归调用 constexpr 函数。但是,我想不出任何实际应用中我曾经想使用如此复杂的计算来定义编译时常量。
因此,即使它可能是一个有趣的功能,我仍然想知道是否需要它(即它多久可以解决宏不够用的情况)。也许看看一些无法用宏解决的现实例子会帮助我改变这种看法。
【问题讨论】:
-
实际上,我的示例不起作用。我必须在函数或对象中声明数组。我一直在用这个成语。
-
@Giorgio:嗯?这如何使其合法化?数组必须使用常量表达式的大小进行初始化。一些编译器(即 GCC)允许您使用动态大小的数组,这是 C99 的一项功能,不是 C++ 的一部分。您能否编辑您的帖子以阐明您将如何做到这一点?
-
如果这里有一个您认为足够的答案,您最好接受它。 :-)
-
我在实现 AES 算法时使用了 constexpr。您必须计算许多元素,它们始终是恒定的,但元素的数量是不同的。我选择计算 256 个数字。它花费了 150 万纳秒(1.5 毫秒),在使用 constexpr 后,它在 1 个处理器滴答声中执行(在我的情况下为 513 纳秒)。而且有时您必须进行更复杂的操作...
-
我实现了一个 SIMD 置换库,其中用户根据位置换(即超立方体置换或位置换/补置换)指定置换,SIMD 代码通过模板扩展生成。需要计算逆排列。如果没有 constexpr,另一种方法是实现一个完整的模板元编程库,用于整数和序列处理。