c++ MSVC无法编译此代码,报告“错误C2131:表达式没有计算为常量'没有constexpr

xyhw6mcr  于 2023-02-17  发布在  其他
关注(0)|答案(1)|浏览(488)

MSVC无法编译以下代码(https://godbolt.org/z/feenYcaen):
错误C2131:表达式的计算结果不是常数
第10行来自MSVC自己的offsetof,我觉得这个语句是常量表达式,即使不是,MSVC运行时不能计算这个吗,这是MSVC的bug吗?

#include <type_traits>
#include <iostream>

struct A{};

template<typename T, A T::*MPtr>
struct KKP {
    private:
   static const std::uintptr_t c =
   ((size_t) & reinterpret_cast<char const volatile&>((((T*)0)->*MPtr)));
};

struct PC {
    A t;
};

size_t f() {
    KKP<PC, &PC::t> ar;
}

事实上,我通过使用成员函数而不是类成员(https://godbolt.org/z/c65eEnvd7)解决了这个问题,但MSVC对我来说变得更加混乱:

#include <type_traits>
#include <iostream>

struct A{};

template<typename T, A T::*MPtr>
struct KKP {
    private:
    static constexpr size_t c() {
       return ((::size_t) & reinterpret_cast<char const volatile&>((((T*)0)->*MPtr)));
    }
};

struct PC {
    A t;
};

size_t f() {
    KKP<PC, &PC::t> ar;
    return 0;
}
cuxqih21

cuxqih211#

offsetof无法在标准C中实现,需要编译器支持-cppreference
从引文中可以看出,这两个代码示例都不符合C
标准。
在应该为constexpr的表达式中存在空指针解引用未定义行为和reinterpret_cast转换。Both do not belong to core constant expressions
核心常量表达式是其计算不会计算以下任何一项的任何表达式:
 8.其求值导致任何形式的核心语言未定义行为的表达式...
 18.重新解释转换
在第二个代码示例中,问题仍然存在,因为函数实际上不是constexpr,并且程序的格式不正确。
constexpr函数必须满足以下要求:

  • 至少存在一组参数值,使得函数的调用可以是核心常量表达式的求值子表达式...(C++23之前)

对于constexpr函数模板和类模板的constexpr成员函数,至少有一个专门化必须满足上述要求。其他专门化仍然被认为是constexpr,即使对这样的函数的调用不能出现在常量表达式中。* 如果模板的任何专门化在被认为是非模板函数时都不能满足constexpr函数的要求,则该模板是病态的。不需要诊断(C++23之前)*. cppreference
考虑example

#include <type_traits>
#include <iostream>

struct A{};

template<typename T, A T::*MPtr>
class KKP {
public:    // make the function public
    static constexpr size_t c() {
       return ((::size_t) & reinterpret_cast<char const volatile&>((((T*)0)->*MPtr)));
    }
};

struct PC {
    A t;
};

size_t f() {
    constexpr auto foo = KKP<PC, &PC::t>::c(); // fails to evaluate in the constexpr context
    return 0;
}

相关问题