我读了一些标准库的 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;
让我感到困惑的是,它在类定义内部使用 constexpr 而在外部使用 const。我的问题是,这是允许的吗?什么情况下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 开始,
A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, the constructor shall be a constexpr constructor and every argument to the constructor shall be a constant expression. that call shall be a constant expression (5.19). Otherwise, every full-expression that appears in its initializer shall be a constant expression.
因此,如果 constexpr int limit = 2 * S::size;无效,则 S::size 不能是常量表达式,然后从 5.19(常量表达式)开始,我看不到上面示例中的标准不允许 2 * S::size 不是常量表达式。
任何人都可以指出我忽略的任何事情吗?非常感谢。
最佳答案
根据 N3225 §5.19p2,S::size 不是常量表达式:
A conditional-expression is a constant expression unless it involves one of the following…
- an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
- [other conditions that don't apply]
请注意我引用的第二个要点如何允许一个本身用常量表达式初始化的完整静态数据成员也是一个常量表达式,但您的 S::size 未初始化。
(旁注:常量表达式是根据条件表达式定义的,因为这就是 C++ 语法的工作方式。)
如果您想知道左值到右值的转换是如何发生的,请参阅§5p9:
Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue (4.1), array-to-pointer (4.2), or function-to-pointer (4.3) standard conversions are applied to convert the expression to a prvalue.
这可能是一个很好的例子,说明如何阅读标准 doesn't make a good reference ,尽管 0x 还没有太多可用的东西。
关于c++ - 混合使用 constexpr 和 const?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4999241/