为什么这个由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: error: 'static constexpr int Item_id::static_n_items()' called in a constant expression static constexpr int bah = static_n_items(); //! Nah.
Visual C ++ 2015报告
constexpr.cpp(12): error C2131: expression did not evaluate to a constant constexpr.cpp(12): note: failure was caused by call of undefined function or one not declared 'constexpr' constexpr.cpp(12): note: see usage of 'Item_id::static_n_items'
我的文本编辑器坚持认为调用中的名称与函数定义中的名称相同。
它似乎与不完整的类有关,因为定义了OUT_OF_CLASS
它可以很好地编译。
但是为什么n_items_
数据有效,以及为什么这样的规则(对我来说没有意义)?
答案 0 :(得分:11)
从内存中,只有在完全定义了类后才会计算成员函数体。
static constexpr int bah = static_n_items();
构成类定义的一部分,但它指的是一个(静态)成员函数,它尚未定义。
解决方案:
将常量表达式推迟到基类并从中派生。
e.g:
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个不同的,看似无关的条款:)
答案 1 :(得分:4)
[class.mem] / 2
在类 member-specification 中,该类在函数体,默认参数, exception-specifications 和默认成员初始化器(包括此类事物)中被视为完整嵌套类)。否则,它在其自己的类 member-specification 中被视为不完整。
在类的static
数据成员的初始值设定项中,类不完整。初始化程序只能看到它前面的成员的声明,并且它可以看到的任何成员函数都被认为是声明但未定义。对已声明但未定义的函数的调用不能是常量表达式。