什么是C ++中的constexpr?

时间:2017-02-08 08:08:28

标签: c++ const constexpr

我对constexpr概念感到困惑,因为我在编译时会对constexpr进行评估,因此它对于性能优化与普通const非常有用。

constexpr int i = 0;
constexpr int& ri = i;

上面的代码返回错误"类型' int&'的引用无效初始化从表达类型' const int'",为什么?

此外,下一个代码有错误:

constexpr int i = 0;
constexpr int* ri = &i;

如果我将constexpr关键字替换为const,则上述所有操作都正常。

4 个答案:

答案 0 :(得分:13)

constexpr int i = 0;
constexpr int  * ri = &i;

第二行是个问题,因为指针不指向const对象。指针本身是const

使用

constexpr int i = 0;
constexpr int const * ri = &i;

解决了这个问题。但是,如果变量是在函数范围内定义的,那仍然是个问题。

constexpr int i = 0;
constexpr int const* ri = &i;

int main() {}

是一个有效的程序。

void foo()
{
   constexpr int i = 0;
   constexpr int const* ri = &i;
}

int main() {}

不是有效的程序。

以下是关于地址常量表达式的C ++ 11标准所说的内容:

  

5.19常量表达式

     

3 ..   地址常量表达式是指针类型的prvalue核心常量表达式,其计算为具有静态存储持续时间的对象的地址,函数的地址,或空指针值或prvalue类型std::nullptr_t的核心常量表达式。

答案 1 :(得分:6)

RE

  

如果我用const替换constexpr字以上都正常工作。”

const int*本质上意味着(const int)*,但您不能以这种方式使用括号。 constexpr int*表示constepxr (int*)(同上注释)。

这是因为constexpr不是该类型的一部分,您不能将类型命名为constexpr int,例如,const是该类型的一部分。

而不是

constexpr int i = 0;
constexpr int& ri = i;

尝试声明constexpr对非const的引用,只需编写

constexpr int i = 0;
constexpr int const& ri = i;

您可以向后阅读,因为riconst int的引用,constexpr(在编译时评估)。

<强>附录

出现C ++ 14要求本地非static constexpr个对象具有自动存储持续时间,以 as-if 为模优化规则。

为了满足这一要求,即为了使代码在编译器之间可移植,如果上述声明在函数中本地出现,则添加static以确保对象所引用的对象的静态存储持续时间:

void oops()
{
    static constexpr int i = 0;      // Necessary with some compilers.
    constexpr int const& ri = i;
}

否则它可能无法用例如g ++,它可能是 C ++ 14和C ++ 11标准所需要的,省略constexpr上的适当约束。

注意:
¹请参阅discussion of R. Sahu's answer。 功能

答案 2 :(得分:3)

正如您所说,function closeDropDown() { $scope.opened = false; } function handleClickEvent(event) { /* When the clicked element is not a child of the element and the dropdown is openend, close the dropdown. */ if ($element.find(event.target).length === 0 && $scope.opened) { closeDropDown(); /* Trigger new digest cycle */ $scope.$apply(); } }; function setListeners() { /* Bind click event to the document, close the dropDown if clicked elsewhere on the page. */ var clickHandler = handleClickEvent; $document.bind('click', clickHandler); /* Remove the used event handlers when destroying the object */ $scope.$on('$destroy', function () { $document.unbind('click', clickHandler); }); } 编译时进行评估。因此,编译时必须可以评估该值。

例如:

constexpr

对于第一行,0在编译时是可评估的,其值为0.

但对于第二行,编译器需要constexpr int i = 0; constexpr int& ri = i; 的地址来执行赋值,这是在运行时确定的。所以这一行会失败。

答案 3 :(得分:1)

这是我的2美分:

constexpr功能定义了在编译期间发生的计算。合理的问题:

  • 允许任何计算
  • 是否有意义

合理的答案:

  • ,因为在编译器内部需要大量机械,资源等,而没有直接需要。

由于该标准允许在constexpr代码中使用非常有限的一组功能。人们可能会争论为什么这个集合而不是更多?那么,以后的标准可能会发展并允许更多。