有人能告诉我为什么这不是一个持续的表达?

Osu*_*ldo 3 c++ constexpr c++11

我正在尝试使用constexpr编写指向成员函数的链接列表.主要是为了好玩,但它可能有一个有用的应用程序.

struct Foo;

using MethodPtr = void (Foo::*)();

struct Node
{
    constexpr Node(MethodPtr method, const Node* next)
        : Method(method)
        , Next(next)
    {}

    constexpr Node Push(MethodPtr method)
    {
        return Node(method, this);
    }

    MethodPtr Method;
    const Node* Next;
};

struct Foo
{
    constexpr static Node GetMethods()
    {
        return Node{&Foo::Method1, nullptr}
            .Push(&Foo::Method2)
            .Push(&Foo::Method3);
    }

    void Method1() {}
    void Method2() {}
    void Method3() {}
};

int main(void)
{
    constexpr Node node = Foo::GetMethods();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码在调用GetMethods()时主要给出了以下错误:

const Node{MethodPtr{Foo::Method3, 0}, ((const Node*)(& Node{MethodPtr{Foo::Method2, 0}, ((const Node*)(& Node{MethodPtr{Foo::Method1, 0}, 0u}))}))}' is not a constant expression
Run Code Online (Sandbox Code Playgroud)

有人请解释为什么这不是一个持续的表达?或者是否有一种替代/正确的方法来实现在编译时构建PTMF列表的目标?

编辑:我正在使用avr-gcc 4.9.2的C++编译器.我将在另一个编译器上尝试此代码.

T.C*_*.C. 6

您正在存储非静态存储持续时间临时值的地址,这在常量表达式中是不允许的.此规则的当前版本位于[expr.const]/5(强调我的):

常量表达式可以是一个glvalue芯常量表达式,其值指的是一个常量表达式的一个允许的结果的实体(如下面所定义),或一个prvalue芯常量表达式,其值是一个对象,其中,该对象和它的子对象:

  • 引用类型的每个非静态数据成员是指一个实体,它是一个常量表达式的允许结果,和

  • 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址,超出此类对象末尾的地址([expr.add]),函数的地址或空指针值.

(C++ 11包含类似的规则(通过地址常量表达式的定义),但是在被C++ 14广义化替换之前,常量表达式规则被多个DR改变了constexpr,我真的不喜欢做标准考古学今天.)

事实上,由于除了返回的每个临时Node创建的内容GetMethods()Node被销毁;,因此Node返回的内容将包含一个悬空指针.