MSVC не может скомпилировать этот код, жалуется на «ошибка C2131: выражение не оценивается как константа» без constexpr

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;
}

Зачем вам нужно использовать offsetof? Какую основную и актуальную проблему это должно решить? Прямо сейчас ваш вопрос действительно является проблемой XY . Пожалуйста, всегда спрашивайте напрямую о фактической и основной проблеме. Также, пожалуйста, найдите время, чтобы прочитать страницы справки , принять участие в туре SO , прочитать Как спросить , а также этот контрольный список вопросов.

Some programmer dude 14.02.2023 11:02

Я просто переносил проект С++ из Linux в Windows. этот код представляет собой мини-набор проблемы пересадки, с которой я сталкиваюсь. И спасибо, я прочитаю эти уроки.

Liupo 14.02.2023 11:14

Обратите внимание, что в библиотеке offsetof используется ->m, а не ->*m. Огромная разница! Также обратите внимание, что стандартной библиотеке разрешено использовать нестандартный код, а коду пользователя — нет. Это одна из причин, по которой offsetof является частью стандартной библиотеки.

BoP 14.02.2023 12:16

Что касается C2131, я предлагаю вам обратиться к этому документу. И не могли бы вы сказать мне, почему код сбивает вас с толку?

Yujian Yao - MSFT 15.02.2023 04:46

@Yujian Yao - MSFT, потому что я думаю, что static const не требуется constant, теперь я полностью понимаю.

Liupo 15.02.2023 07:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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;
}

Другие вопросы по теме