Ограничения на то, что можно использовать в константном выражении, определяются в основном как список негативов.Есть куча вещей, которые вы не можете оценить ( [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)
обеспечивает некоторое значение, которое дает согласованный общий порядок во время компиляции и , что оно дает тот же ответ во время выполнения.Что ... интересная головоломка.