为什么这个constexpr静态成员函数在被调用时不被视为constexpr?

时间:2016-05-12 17:56:32

标签: c++ constexpr

为什么这个由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_数据有效,以及为什么这样的规则(对我来说没有意义)?

2 个答案:

答案 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数据成员的初始值设定项中,类不完整。初始化程序只能看到它前面的成员的声明,并且它可以看到的任何成员函数都被认为是声明但未定义。对已声明但未定义的函数的调用不能是常量表达式。