constexpr真的需要吗?

Gio*_*gio 16 c++ constexpr c++11

我一直在constexpr研究C++ 的新功能,但我并不完全理解它的必要性.

例如,以下代码:

constexpr int MaxSize()
{
    ...

    return ...;
}

void foo()
{
    int vec[MaxSize()];
}
Run Code Online (Sandbox Code Playgroud)

可以替换为:

int MaxSize()
{
    ...

    return ...;
}

static const int s_maxSize = MaxSize();

foo()
{
    int vec[s_maxSize];
}
Run Code Online (Sandbox Code Playgroud)

更新

第二个例子实际上不是标准的ISO C++(感谢几个用户指出这一点),但某些编译器(例如gcc)支持它.因此,这不是const使程序有效,而是gcc支持这种非标准功能的事实.(据我所知,只有当数组被定义为函数或方法的本地数据时才有可能,因为在编译时必须知道全局数组的大小.)如果我编译没有选项-std=c++98 -pedantic-errors,甚至代码

int MaxSize()
{
    return 10;
}

void foo()
{
    int vec[MaxSize()];
}
Run Code Online (Sandbox Code Playgroud)

将使用gcc编译.

因此,考虑到目前为止的反馈(以及我在同一时间进行的一些进一步阅读),我将尝试重新解释我的问题.

const大量使用关键字.随着const我可以定义有其整个生命周期内某一特定值的常数.可以使用任何表达式初始化常量,该表达式被计算一次,即创建常量时.对于这些情况,我认为这constexpr是非常无用的:它将引入一个非常小的优化,因为定义常量值的表达式将在编译时而不是运行时计算.每次我需要一个复杂初始化的运行时常量时我都会使用关键字const.

因此constexpr,在我们需要在编译时初始化常量的情况下,可能会派上用场.一个示例是矢量定义:标准不支持在运行时定义大小.另一个示例是具有一个或多个非类型参数的模板.

在这种情况下,我通常使用宏:

#define MAX_SIZE (10)

void foo()
{
    int vec[MAX_SIZE];
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我理解正确,constexpr函数比宏更强大,因为它们允许constexpr在定义中递归调用函数.但是,我想不出任何实际的应用程序,我曾想用这种复杂的计算来定义编译时常量.

因此,即使它可能是一个有趣的功能,我仍然想知道是否需要它(即它可以解决宏不足的情况).也许看一些用宏无法解决的现实例子可以帮助我改变这种观点.

Omn*_*ous 18

int vec[s_maxSize];在第二个例子中实际上是非法的,因此在C++中是不可能的.但是你的第一个例子是完全合法的C++ 0x.

所以有你的答案.你实际上无法做你在C++中提出的建议.它只能在C++ 0x中完成constexpr.

我还想指出,这段代码也适用于C++ 0x.在C++中执行此操作需要一些非常精美的类模板.

constexpr unsigned int gcd(unsigned int const a, unsigned int const b)
{
   return (a < b) ? gcd(b, a) : ((a % b == 0) ? b : gcd(b, a % b));
}

char vec[gcd(30, 162)];
Run Code Online (Sandbox Code Playgroud)

当然,在C++ 0x中,您仍然必须使用三元运算符而不是if语句.但是,它比你在C++中强制使用的模板版本更有效,并且更容易理解:

template <unsigned int a, unsigned int b>
class gcdT {
 public:
   static unsigned int const value = gcdT<b, a % b>::value;
};

template <unsigned int a>
class gcdT<a, 0> {
 public:
   static unsigned int const value = a;

};

char vec[gcdT<30, 162>::value];
Run Code Online (Sandbox Code Playgroud)

然后,当然,在C++中你仍然需要编写的gcd,如果你需要在运行时计算的东西,因为模板不能在运行时改变参数一起使用的功能.和C++ 0x中必须知道该函数的结果完全是由在参数的传递,这是一个只能在C++编译器扩展来表达一个事实决定的额外的优化提升.


Fai*_*ali 7

你可以用constexpr做一些你无法用宏或模板做的事情是在编译时解析/处理字符串:用constexpr编译时间字符串处理(改变大小写,排序等).作为前面链接的一小段摘录,constexpr允许用户编写如下代码:

#include "my_constexpr_string.h"
int main()
{
   using namespace hel;
   #define SDUMP(...) static_assert(__VA_ARGS__, "")

   SDUMP(tail("abc") == "bc");
   SDUMP( append("abc", "efgh") == "abcefgh" );
   SDUMP( prepend("abc", "efgh") == "efghabc" );
   SDUMP( extract<1,3>("help") == "el" );
   SDUMP( insert<1>("jim", "abc") == "jabcim" );
   SDUMP( remove("zabzbcdzaz", 'z') == "abbcdazzzz" );
   SDUMP( erase("z12z34z5z", 'z') == "12345"  );
   SDUMP( map("abc", ToUpper()) == "ABC" );
   SDUMP( find("0123456777a", '7') == 7 );
   SDUMP( isort("03217645") == "01234567");  
}
Run Code Online (Sandbox Code Playgroud)

作为一个有用的例子,它可以促进编译时计算/构造某些解析器和使用文字字符串指定的正则表达式有限状态机.您可以在编译时推迟处理的处理越多,在运行时执行的处理就越少.


Bli*_*ndy -4

根据这个推理,你一般不需要常量,甚至不需要#define。没有内联函数或任何东西。

constexpr与许多关键字一样,的目的是让您更好地表达您的意图,以便编译器准确理解您想要的内容,而不仅仅是您告诉它的内容,因此它可以在幕后为您做更好的优化。

在此示例中,它允许您编写可维护的函数来计算向量大小,而不仅仅是一遍又一遍地复制和粘贴的纯文本。

  • -1 - 这根本没有真正回答OP的问题,而且还不必要地刻薄。 (4认同)