混合使用constexpr和const?

时间:2011-02-15 01:57:16

标签: c++ c++11 const clang

我读了一些标准库的CLang实现,它让我对const和constexpr感到困惑。

template<class _Tp, _Tp __v>
struct integral_constant
{
    static constexpr _Tp value = __v;
};

template<class _Tp, _Tp __v>
const _Tp integral_constant<_Tp, __v>::value;

令我困惑的是,它在类定义和const外部使用constexpr。我的问题是,是允许的吗?在什么情况下const和constexpr可以互换使用?当然constexpr函数不能应用于const,所以我说的是const数据和constexpr数据。

我确实读过一些标准草案和提案 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf, 但它让我感到更加困惑。所以我还有一些问题,

在N2235中,它明确指出,const数据不保证是编译时常量,参见下面的例子,

struct S {
    static const int size;
};
const int limit = 2 * S::size; // dynamic initialization
const int S::size = 256;

和constexpr应该解决这个问题,所以至少在这种情况下,不允许使用constexpr,

struct S {
    static const int size;
};
constexpr int limit = 2 * S::size; // shall be error in my understanding
const int S::size = 256;

但是,在阅读了C ++标准草案N3225之后,我看到没有明确说明上述示例会导致错误。特别是,从7.1.5 / 9,

  

一个constexpr说明符   对象声明声明对象   作为常数。这样的对象应该有   字面类型,应初始化。   如果它是由构造函数初始化的   打电话,构造函数应该是   constexpr构造函数和每一个   构造函数的参数应为a   不断表达。那个电话应该   是一个常数表达式(5.19)。   否则,每一个完整的表达   在其初始化器中出现的应为a   不断表达。

因此,如果constexpr int limit = 2 * S :: size;是无效的,那么S :: size不能是一个常量表达式,那么从5.19(常量表达式),我看不到上面例子中的标准禁止2 * S :: size不是常量表达式。

有人能指出我忽略的任何事情吗?非常感谢你。

2 个答案:

答案 0 :(得分:4)

根据N3225§5.19p2:

,S :: size不是常量表达式
  

条件表达式是一个常量表达式,除非它涉及以下之一...

     
      
  • 左值 - 右值转换(4.1),除非适用于      
        
    • 整数或枚举类型的glvalue,它引用具有前面初始化的非易失性const对象,用常量表达式初始化,或
    •   
    • [其他不适用的条件]
    •   
  •   

注意我引用的第二个项目符号点是如何允许一个整数静态数据成员,它本身用常量表达式初始化也是一个常量表达式,但你的S :: size是未初始化的。

(旁注:常量表达式是根据条件表达式定义的,因为这就是C ++语法的工作原理。)

如果您想知道左值到右值的转换是如何发生的,请参阅§5p9:

  

每当glvalue表达式作为操作符的操作数出现时,该操作符需要该操作数的prvalue,lvalue-to-rvalue(4.1),array-to-pointer(4.2)或function-to-pointer(4.3)应用标准转换以将表达式转换为prvalue。

这可能是阅读标准doesn't make a good reference的一个很好的例子,尽管还没有其他的可用于0x。

答案 1 :(得分:2)

“它的初始化程序中出现的每个完整表达式都应该是一个常量表达式”

S::size不是常量表达式,因此它不能出现在常量表达式的初始化中。