Я недавно задал вопрос здесь (Detecting instance method constexpr with SFINAE), где я пытался выполнить некоторое обнаружение constexpr во время компиляции. В конце концов, я понял, что для этого можно использовать noexcept
: любое постоянное выражение также равно noexcept
. Поэтому я собрал следующую технику:Constexpr decltype
template <class T>
constexpr int maybe_noexcept(T && t) { return 0; }
...
constexpr bool b = noexcept(maybe_noexcept(int{}));
Это работает и b
верно, как и следовало ожидать, как нуль-инициализации int
является константным выражением. Он также корректно возвращает нуль, если это необходимо (если я изменю int
на другой подходящий тип).
Далее, я хотел проверить, есть ли что-то constexpr
двигаться конструктивно. Так что я сделал это:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
И опять же, это работает должным образом для int
, или определенного пользователем типа. Однако это проверяет, что тип имеет как конструктор constexpr по умолчанию, так и конструктор перемещения constexpr. Таким образом, чтобы решить эту проблему, я попытался изменить к declval:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
Это приводит к b
ложна в GCC 5.3.0 (не может использовать лязг для любого из этого, потому что лязг не правильно сделать постоянной выражения noexcept
). Нет проблем, я говорю, должно быть потому, что declval
(интересно) не отмечено constexpr
. Итак, я пишу свою собственную наивную версию:
template <class T>
constexpr T&& constexpr_declval() noexcept;
Да, это наивно по сравнению с тем, как стандартная библиотека делает это, как он будет задыхаться от пустоты и, вероятно, других вещей, но это нормально сейчас. Поэтому я стараюсь снова:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
Это все еще не работает, b
всегда ложно. Почему это не считается постоянным выражением? Является ли это ошибкой компилятора, или я не понимаю фундаментальных данных о constexpr
? Похоже, есть какое-то странное взаимодействие между constexpr
и неоценимыми контекстами.
@Cameron Вторая часть того, что вы сказали, конечно, верна, но первая технически - нет. Каждое постоянное выражение * является * '' noexcept'', но это не так. Однако возврат функции '' constexpr'' не всегда является постоянным выражением. –
Ваш вызов функции не является постоянным выражением, потому что он не определен ([expr.const] /2.3) – 0x499602D2