为什么这个由//! Nah
注释标识的constexpr
static
成员函数在调用时不被视为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()"static 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个不同的、看似无关的子句:)
[class.mem]/2
在类成员规范中,该类在函数体、默认参数、异常规范和默认成员初始值设定项(包括嵌套类中的此类内容)内被视为完整的。否则,它在其自己的类成员规范中被视为不完整。
在类的static
数据成员的初始值设定项中,该类是不完整的。初始值设定项只能看到它前面的成员声明,它可以看到的任何成员函数都被视为已声明但未定义。对已声明但未定义的函数的调用不能是常量表达式。