简体   繁体   English

你可以调用一个 constexpr 函数来分配一个带有前向声明的 constexpr 值吗?

[英]Can you call a constexpr function to assign a constexpr value with a forward declaration?

I found myself in a weird spot, with the error message "expression did not evaluate to a constant":我发现自己处于一个奇怪的位置,错误消息“表达式未计算为常数”:

constexpr uint64 createDynamicPipelineStateMask();

static inline constexpr uint64 dynamic_state_mask = createDynamicPipelineStateMask();


struct CullMode
{
    static constexpr inline bool bIsDynamicState = false;
    static constexpr inline uint64 mask = 0;
};

constexpr uint64 createDynamicPipelineStateMask()
{
    uint64 dynamic_mask = 0;
    if constexpr (CullMode::bIsDynamicState) dynamic_mask |= CullMode::mask;

    return dynamic_mask;
}

Now I guess I could just move the constexpr value to below the definition, but I wanted to know the answer to this question.现在我想我可以将 constexpr 值移到定义之下,但我想知道这个问题的答案。 I know that it's compiler, and not the linker that needs the full definition of the constexpr function, but the compiler has it right below.我知道它是编译器,而不是需要 constexpr 函数的完整定义的链接器,但编译器就在下面。

I know that it's compiler, and not the linker that needs the full definition of the constexpr function, but the compiler has it right below .我知道它是编译器,而不是需要 constexpr 函数的完整定义的链接器,但编译器在下面有它

The behavior of the program can be understood using expr.const#5 which states:可以使用expr.const#5来理解程序的行为,其中指出:

5. An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following: 5.表达式 E 是核心常量表达式,除非根据抽象机 ([intro.execution]) 的规则对 E 的求值将求值以下之一:

5.2 an invocation of an undefined constexpr function ; 5.2调用未定义的 constexpr 函数

(emphasis mine) (强调我的)

This means that when writing这意味着当写

//------------vvvvvvvvv--------------------------> note the constexpr here, this is not allowed because the call expression cannot be used in a constexpr context until the function is defined
static inline constexpr int dynamic_state_mask = createDynamicPipelineStateMask();

the call expression createDynamicPipelineStateMask() at this point is an invocation of an undefined constexpr function and so the initializer is not a constant expression according to the above quoted statement which in turn means that it cannot be used as an initializer to initialize dynamic_state_mask .此时的调用表达式createDynamicPipelineStateMask()是对未定义的 constexpr 函数的调用,因此根据上面引用的语句,初始化程序不是常量表达式,这反过来意味着它不能用作初始化dynamic_state_mask的初始化程序。 Basically, you can't use the call expression createDynamicPipelineStateMask() in a constexpr context until the function is defined.基本上,在定义函数之前,您不能在constexpr 上下文中使用调用表达式createDynamicPipelineStateMask()


But the following is perfectly fine.但以下是完全没问题的。

//------------v-------------------------->note no constexpr here, this is allowed
static inline  int dynamic_state_mask = createDynamicPipelineStateMask();

This time, even though createDynamicPipelineStateMask() does not evaulate to a constant expression, it can still be used as an initializer to initialize dynamic_state_mask as we have removed the constexpr specifier from the left hand side of the declaration.这一次,即使createDynamicPipelineStateMask()没有评估为常量表达式,它仍然可以用作初始化器来初始化dynamic_state_mask ,因为我们已经从声明的左侧删除了constexpr说明符。 Basically this isn't a constexpr context and so using the call expression as an initializer is fine.基本上这不是一个constexpr 上下文,因此使用调用表达式作为初始化程序很好。


Perhaps a contrived example might clear this further:也许一个人为的例子可能会进一步说明这一点:

constexpr int func();

//constexpr int i = func();   //not allowed as the call expression func() at this point is an invocation of an undefined constexpr function and so the initializer is not a constant expression

int i = func();               //allowed
constexpr int func()
{
    return 4;
}
constexpr int j = func();     //allowed

Demo Clang&Gcc ,演示 Clang&Gcc ,

MSVC Demo MSVC 演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM