Why is calling a constexpr function with a member array not a constant expression?

烂漫一生 提交于 2019-12-03 09:28:47
Rakete1111

MSVC is correct. Length(temp1) is not a constant expression. From [expr.const]p2

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

temp1 evaluates this implicitly (because you are referring to this->temp1), and so you don't have a constant expression. gcc and clang accept it because they support VLAs as an extension (try compiling with -Werror=vla or -pedantic-errors).

Why isn't this allowed? Well, you could access the underlying elements and potentially modify them. This is completely fine if you are dealing with a constexpr array or an array that is being evaluated as a constant expression, but if you are not, then you cannot possibly have a constant expression as you will be manipulating values that are set at run time.

Mi-He
Length(decltype(temp1){})

seems to work.

Unfortunately, I cannot comment, but Mehrdad 's solution is wrong. The reason: it is not technically undefined behavior but it is undefined behavior. During constexpr evaluation, the compiler must catch undefined behavior. Therefore, the code is ill-formed.

Your question's already been answered, but in terms of how to "fix" it, a quick-and-dirty way is to replace

Length(temp1)

with

Length(*(true ? NULL : &temp1))

which I think is technically undefined behavior but practically going to work fine for MSVC.

If you need a solution that works despite the UB, you can change Length to use a pointer:

template<typename T, std::size_t N>
constexpr std::size_t Length(const T(*)[N]) {
    return N;
}

and then you can use Length(true ? NULL : &temp1).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!