简体   繁体   中英

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. 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.

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 .

The behavior of the program can be understood using expr.const#5 which states:

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.2 an invocation of an undefined constexpr function ;

(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 . Basically, you can't use the call expression createDynamicPipelineStateMask() in a constexpr context until the function is defined.


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. Basically this isn't a constexpr context and so using the call expression as an initializer is fine.


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 ,

MSVC Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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