2011-02-15 101 views
7

我读了一点CLang标准库的实现,它让我在const和constexpr上感到困惑。混合使用constexpr和const?

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; 

什么让我困惑的是,它使用constexpr里面的类定义和const外。我的问题是,这是允许的吗?而在什么情况下我可以交换使用const和constexpr?当然,constexpr函数不能应用于const,所以我正在讨论const数据和constexpr数据。

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

在N2235,它明确指出,常量数据不能保证是一个编译时间常数,请看下面的例子,

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; 

然而,读℃后++标准草案N3225,我看到无处明确指出的是,上述实施例应导致错误。特别地,从7.1.5/9,

在 对象声明使用的constexpr指定符为const对象 。这样的对象应该具有文字类型并且应该被初始化。 如果通过构造函数 进行初始化,则构造函数应该是 constexpr构造函数,并且构造函数的每个 参数应为 常量表达式。该呼叫应该是 是一个常数表达式(5.19)。 否则, 出现在其初始化程序中的每个全表达式应为 常量表达式。

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

有人可以指出我忽略的任何东西吗?非常感谢你。

回答

3

的s ::大小不是常量表达式根据N3225§5.19p2:

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

  • 左值向右值转换(4。1),除非它被施加到
    • 整型或枚举类型的glvalue其指的是非易失性const对象与前面的初始化,以恒定表达初始化,或者
    • [其它不条件申请]

注意第二个小点我引用了如何让这本身就是一个常量表达式也可以是常量表达式初始化的整体静态数据成员,但你的S ::大小是未初始化。

(边注:常量表达式在条件表达式来定义,因为这是C++的语法如何运作)

如果你想知道如何左值到右值转换情况,请参阅§ 5P9:

每当glvalue表达显示为操作者的操作数预计,该操作数,左值到右值(4.1),阵列到指针(4.2),或功能到prvalue - 指针(4.3)标准转换应用于将表达式转换为prvalue。

这可能是阅读标准doesn't make a good reference的一个很好的例子,虽然0x没有其他可用的东西了。

+0

嗨,谢谢。我忽略了它。然而,尽管我确实发现很多人在互联网上说过这些,但我仍然没有发现标准提到的地方:赋值运算符期望右边是右值,二元算术运算符期望它们的两个操作数都是右值。 – user534498 2011-02-15 06:01:26

2

S::size不是一个常量表达式“出现在它的初始值应是常量表达式每满表达”,因此不能出现在常量表达式的初始化。

+1

我的问题其实是:为什么S :: size不是一个常量表达式?我多次阅读5.19(常量表达式),并没有发现它提到了S :: size不是一个常量表达式的情况。 – user534498 2011-02-15 03:34:03