为什么这个由
constexpr
注释标识的 static
//! Nah
成员函数在调用时不显示为 constexpr
?
struct Item_id
{
enum Enum
{
size, position, attributes, window_rect, max_window_size, _
};
static constexpr int n_items_ = _; // OK
constexpr auto member_n_items() const -> int { return _; } // OK
static constexpr auto static_n_items() -> int { return _; } // OK
static constexpr int so_far = n_items_; // OK
#ifndef OUT_OF_CLASS
static constexpr int bah = static_n_items(); //! Nah.
#endif
};
constexpr auto n_ids() -> int { return Item_id().member_n_items(); } // OK
auto main() -> int
{
#ifdef OUT_OF_CLASS
static constexpr int bah = Item_id::static_n_items(); // OK
#endif
}
MinGW g++ 5.1 报告
constexpr.cpp:12:46:错误:在常量表达式中调用“static constexpr int Item_id::static_n_items()” 静态 constexpr int bah = static_n_items(); //!不。
Visual C++ 2015 报告
constexpr.cpp(12):错误 C2131:表达式未计算为常量 constexpr.cpp(12):注意:失败是由于调用未定义的函数或未声明“constexpr”的函数引起的 constexpr.cpp(12):注意:请参阅 'Item_id::static_n_items' 的用法
我的文本编辑器坚持要求调用中的名称与函数定义中的名称相同。
它似乎与不完整的类有关,因为定义了
OUT_OF_CLASS
它可以很好地编译。
但是为什么
n_items_
数据有效,为什么这样的规则(对我来说没有意义)?
根据记忆,只有在类完全定义后才会计算成员函数体。
static constexpr int bah = static_n_items();
构成类定义的一部分,但它指的是尚未定义的(静态)成员函数。
解决方案:
将常量表达式推迟到基类并从中派生。
例如:
struct Item_id_base
{
enum Enum
{
size, position, attributes, window_rect, max_window_size, _
};
static constexpr int n_items_ = _; // OK
constexpr auto member_n_items() const -> int { return _; } // OK
static constexpr auto static_n_items() -> int { return _; } // OK
static constexpr int so_far = n_items_; // OK
};
struct Item_id : Item_id_base
{
#ifndef OUT_OF_CLASS
static constexpr int bah = static_n_items(); // now OK
#endif
};
constexpr auto n_ids() -> int { return Item_id().member_n_items(); } // OK
auto main() -> int
{
#ifdef OUT_OF_CLASS
static constexpr int bah = Item_id::static_n_items(); // OK
#endif
}
您认为为什么标准不允许这样做?
因为这是非法的:
struct Item_id
{
// ... etc.
#ifndef OUT_OF_CLASS
static constexpr int bah;// = static_n_items(); //! Nah.
#endif
};
constexpr int Item_id::bah = static_n_items();
并且 constexpr 必须有 constexpr 定义。我们唯一可以定义它的地方是在它的声明期间......
...因此通过推论,它不能引用任何尚未定义其主体的函数。
我不知道在哪里可以找到所有这些标准。可能有 5 个不同的、看似无关的子句:)
[类.mem]/2
在类成员规范中,该类在函数体、默认参数、异常规范和默认成员初始值设定项(包括嵌套类中的此类内容)中被视为完整。否则,它在自己的类中被视为不完整成员规范。
在类的
static
数据成员的初始化程序中,该类是不完整的。初始化程序只能看到它前面的成员的声明,并且它可以看到的任何成员函数都被视为已声明但未定义。对已声明但未定义的函数的调用不能是常量表达式。