MSVC не может скомпилировать приведенный ниже код (https://godbolt.org/z/feenYcaen):
ошибка C2131: выражение не является константой
Строка 10 взята из собственного offsetof
MSVC. Я думаю, что это утверждение является постоянным выражением, даже если это не так, не может ли MSVC вычислить это во время выполнения? Это ошибка MSVC?
#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;
}
Я просто переносил проект С++ из Linux в Windows. этот код представляет собой мини-набор проблемы пересадки, с которой я сталкиваюсь. И спасибо, я прочитаю эти уроки.
Обратите внимание, что в библиотеке offsetof используется ->m
, а не ->*m
. Огромная разница! Также обратите внимание, что стандартной библиотеке разрешено использовать нестандартный код, а коду пользователя — нет. Это одна из причин, по которой offsetof
является частью стандартной библиотеки.
Что касается C2131, я предлагаю вам обратиться к этому документу. И не могли бы вы сказать мне, почему код сбивает вас с толку?
@Yujian Yao - MSFT, потому что я думаю, что static const
не требуется constant
, теперь я полностью понимаю.
offsetof не может быть реализован в стандартном C++ и требует компилятора поддержка - cppreference
Из цитаты сразу следует, что оба примера кода не соответствуют стандарту C++.
Есть неопределенное поведение разыменования нулевого указателя и преобразование reinterpret_cast
в выражении, которое должно быть constexpr
.
Оба не относятся к основным константным выражениям:
Базовое константное выражение — это любое выражение, вычисление которого не оценивайте ни одно из следующего:
8. выражение, оценка которого приводит к любой форме неопределенного поведения основного языка...
18. переинтерпретировать_cast
Проблема все еще сохраняется во втором примере кода, потому что функция на самом деле не является constexpr
, а программа имеет неправильный формат.
Функция constexpr должна удовлетворять следующим требованиям:
- существует по крайней мере один набор значений аргументов, такой что вызов функция может быть оцениваемым подвыражением базовой константы выражение... (до С++ 23)
Для шаблонов функций constexpr и функций-членов шаблонов классов constexpr по крайней мере одна специализация должна удовлетворять вышеупомянутым требованиям. Другие специализации по-прежнему считаются constexpr, хотя вызов такой функции не может появляться в постоянном выражении. Если никакая специализация шаблона не удовлетворяет требованиям к функции constexpr, если рассматривать ее как функцию, не являющуюся шаблоном, то шаблон имеет неправильный формат, и диагностика не требуется (до C++23). cppreference
Рассмотрим пример
#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;
}
Зачем вам нужно использовать
offsetof
? Какую основную и актуальную проблему это должно решить? Прямо сейчас ваш вопрос действительно является проблемой XY . Пожалуйста, всегда спрашивайте напрямую о фактической и основной проблеме. Также, пожалуйста, найдите время, чтобы прочитать страницы справки , принять участие в туре SO , прочитать Как спросить , а также этот контрольный список вопросов.