C ++ constexpr не работает с reinterpret_cast [duplicate]

Чтобы установить стороннюю банку, пожалуйста, вызовите команду, как показано ниже

mvn install:install-file -DgroupId= -DartifactId= -Dversion= -Dpackaging=jar -Dfile=path
14
задан 101010 25 June 2014 в 02:11
поделиться

2 ответа

TL; DR

clang верен, это известно gcc. Вы можете использовать intptr_t вместо этого и использовать, когда вам нужно использовать это значение, или если это не работает, то оба gcc и clang поддерживают небольшую задокументированную работу, которая должна разрешить ваш конкретный вариант использования.

Подробности

Итак, clang верна на этом, если мы перейдем к черновому стандарту C ++ 11 5.19 Константные выражения paragraph 2 говорит:

Условное выражение является выражением постоянной константы, если оно не включает одно из следующих значений как потенциально оцененное subexpression [...]

и включает следующую марку:

- reinterpret_cast (5.2.10);

Одним простым решением было бы использовать intptr_t :

static constexpr intptr_t ptr = 0x1;

, а затем использовать позже, когда вам нужно его использовать:

reinterpret_cast<void*>(foo::ptr) ;

Возможно, соблазнительно оставить это, но эта история становится интереснее. Это известно и все еще открывает ошибку gcc, см. Ошибка 49171: [C ++ 0x] [constexpr] Константные выражения поддерживают reinterpret_cast . Из обсуждения видно, что у разработчиков gcc есть некоторые явные примеры использования:

Я считаю, что нашел подходящее использование reinterpret_cast в постоянных выражениях, используемых в C ++ 03:

//---------------- struct X {  X* operator&(); };

X x[2];

const bool p = (reinterpret_cast<X*>(&reinterpret_cast<char&>(x[1]))
- reinterpret_cast<X*>(&reinterpret_cast<char&>(x[0]))) == sizeof(X);

enum E { e = p }; // e should have a value equal to 1
//----------------

В основном эта программа демонстрирует технику, на основе функции библиотеки адресов C ++ 11 на основе и, исключая reinterpret_cast безоговорочно из постоянных выражений на базовом языке, эта полезная программа недействителен и сделает невозможным объявление addressof как функции constexpr.

, но не смог получить исключение, вырезанное для этих случаев использования, см. закрытые вопросы 1384 :

Хотя reinterpret_cast разрешен в выражениях константы адреса в C ++ 03, это ограничение было реализовано в некоторых компиляторах и не доказало, что оно нарушает значительные количества кода. CWG посчитал, что осложнения, связанные с указателями, чьи изменения изменились (арифметика указателя и разыменование не могли быть разрешены на таких указателях), перевешивали возможную полезность ослабления ограничения тока.

НО , по-видимому, gcc и clang поддерживают небольшое документированное расширение, которое позволяет постоянно складывать непостоянные выражения, используя __ builtin_constant_p (exp) , и поэтому следующие выражения принимаются как gcc и clang:

static constexpr const void* ptr = 
  __builtin_constant_p( reinterpret_cast<const void*>(0x1) ) ? 
    reinterpret_cast<const void*>(0x1) : reinterpret_cast<const void*>(0x1)  ;

Поиск документации для этого почти невозможно, но это llvm commit является информативным со следующими фрагментами, которые содержат интересное чтение:

< blockquote>
  • поддерживает gcc __builtin_constant_p ()? ...: ... складной взлом в C ++ 11

и:

+ // __builtin_constant_p? : является магическим и всегда является потенциальной константой.

и:

  • // Этот макрос заставляет свой аргумент быть сложенным, даже если это не
  • // иначе константное выражение.
  • определяет fold (x) (__builtin_constant_p (x)? (x): (x))

Мы можем найти более формальное объяснение этой функции в электронной почте gcc-patches: C постоянные выражения, VLA и т. д. исправления , который гласит: :

Кроме того, правила для __builtin_constant_p, вызываемые как условие условного выражения в реализации, более расслаблены, чем правила в формальной модели: выбранная половина условного выражения полностью свернута без учета того, формально является постоянным выражением, поскольку __builtin_constant_p проверяет полностью сложенный аргумент.

12
ответ дан Shafik Yaghmour 24 August 2018 в 05:31
поделиться

Кланг прав. Результат реинтерпрет-литья никогда не является постоянным выражением (см. C ++ 11 5.19 / 2).

Цель константных выражений состоит в том, что они могут быть аргументированы как значения, а значения должны действительны. То, что вы пишете, не является допустимым указателем (поскольку это не адрес объекта или связанный с адресом объекта по арифметике указателя), поэтому вам не разрешено использовать его в качестве постоянного выражения. Если вы просто хотите сохранить номер 1, сохраните его как uintptr_t и сделайте реинтерпрет на используемом сайте.


. В стороне, чтобы немного поразмыслить над понятием «действительные указатели», рассмотрите следующие указатели constexpr:

int const a[10] = { 1 };
constexpr int * p1 = a + 5;


constexpr int b[10] = { 2 };
constexpr int const * p2 = b + 10;

// constexpr int const * p3 = b + 11;    // Error, not a constant expression

// static_assert(*p1 == 0, "")           // Error, not a constant expression

static_assert(p2[-2] == 0, "");          // OK

// static_assert(p2[1] == 0, "");        // Error, "p2[2] would have UB"

static_assert(p2 != nullptr, "");        // OK

// static_assert(p2 + 1 != nullptr, ""); // Error, "p2 + 1 would have UB"

Оба p1 и p2 являются постоянными выражениями. Но независимо от того, является ли результат арифметики указателя постоянным выражением, зависит от того, не является ли это UB! Подобное рассуждение было бы существенно невозможным, если бы значения констант reinterpret_casts были постоянными.

11
ответ дан Kerrek SB 24 August 2018 в 05:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: