Ответ 1
Ограничения на то, что можно использовать в константном выражении, определяются в основном как список негативов. Есть куча вещей, которые вы не можете оценить ([expr.const]/2 в C+ +1 4) и некоторые вещи, значения которых должны быть получены ([expr.const]/4 в C+ +1 4). Этот список меняется от стандарта к стандарту, становясь все более уместным со временем.
В попытке оценить:
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 случайно отвергает.
† Хотя мы просто заявляем с помощью fiat, что std::less()(p, q)
предоставляет некоторое значение, которое дает согласованный общий порядок во время компиляции и дает тот же ответ во время выполнения. Что... интересная головоломка.