Почему 0 == ("abcde" +1) не является константным выражением? - PullRequest
0 голосов
/ 29 января 2019

Почему следующий код не компилируется?

// source.cpp

int main()
{
   constexpr bool result = (0 == ("abcde"+1));
}

Команда компиляции:

$ g++ -std=c++14 -c source.cpp

Вывод:

source.cpp: In function ‘int main()’:
source.cpp:4:32: error: ‘((((const char*)"abcde") + 1u) == 0u)’ is not a constant expression
 constexpr bool result = (0 == ("abcde"+1));
                         ~~~^~~~~~~~~~~~~~~

Я используюgcc6.4.

1 Ответ

0 голосов
/ 30 января 2019

Ограничения на то, что можно использовать в константном выражении, определяются в основном как список негативов.Есть куча вещей, которые вы не можете оценить ( [expr.const] / 2 в C ++ 14) и некоторые вещи, значения которых должны привести к ( [expr.const]/ 4 в C ++ 14).Этот список меняется от стандарта к стандарту, со временем он становится все более разрешающим.

При попытке оценить:

constexpr bool result = (0 == ("abcde"+1));

нет ничего, что нам не разрешено оценивать, и мы нене может быть никаких результатов, которых нам не разрешеноНет неопределенного поведения и т. Д. Это совершенно правильное, если нечетное, выражение.Просто тот, который gcc 6.3 запрещает - это ошибка компилятора.gcc 7+, clang 3.5+, msvc все скомпилируют.

Похоже, что в этом вопросе много путаницы, и во многих комментариях предполагается, что, поскольку значение строкового литерала, например "abcde", неизвестно до времени выполнения, вы не можете ничего сделать с таким указателем во время постоянной оценки.Важно объяснить, почему это не так.

Начнем с объявления вроде:

constexpr char const* p = "abcde";

Этот указатель имеет некоторое значение .Допустим, N.Главное, что все, что вы можете сделать, чтобы попытаться наблюдать N во время постоянной оценки, будет плохо сформировано.Вы не можете привести его к целому числу , чтобы прочитать значение.Вы не можете сравнить его с другой, не связанной строкой (в виде [expr.rel] /4.3):

constexpr char const* q = "hello";
p > q; // ill-formed
p <= q; // ill-formed
p != q; // ok, false

Мы можем точно сказать, что p != q, потому что где бы они ни указывали, они явно разные.Но мы не можем сказать, кто идет первым.Такое сравнение является неопределенным поведением, а неопределенное поведение не разрешено в константных выражениях.

Вы можете только сравнивать с указателями в одном и том же массиве:

constexpr char const* a = p + 1; // ok
constexpr char const* b = p + 17; // ill-formed
a > p; // ok, true

Где бы ни указывалось p, мы знаем , что a указывает после него.Но нам не нужно знать N, чтобы определить это.

В результате фактическое значение N во время постоянной оценки является более или менее несущественным.

"abcde" где-то ..."abcde"+1 указывает на единицу позже, и имеет значение "bcde".Независимо от того, куда он указывает, вы можете сравнить его с нулевым указателем (0 является константой нулевого указателя), и он не является нулевым указателем, следовательно, сравнение оценивается как ложное.

Это очень хорошосформированная константная оценка, которую gcc 6.3 случайно отклонил.

Хотя мы просто заявляем по указу, что std::less()(p, q) обеспечивает некоторое значение, которое дает согласованный общий порядок во время компиляции и , что оно дает тот же ответ во время выполнения.Что ... интересная головоломка.

...