Я однажды написал (EDIT: см. ниже ограничения и объяснения). Из https://stackoverflow.com/a/10287598/34509 :
template
constexpr typename remove_reference::type makeprval(T && t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
Однако существует много видов постоянных выражений. Вышеуказанный ответ обнаруживает постоянные выражения prvalue.
Выражение noexcept(e)
дает false
, если f e
содержит
throw
, typeid
. Обратите внимание, что шаблон функции makeprval
не объявлен noexcept
, поэтому вызов должен быть постоянным выражением для первого пулю не применять, и это то, что мы злоупотребляем. Нам также нужны другие патроны, но, к счастью, и throw
, и метаданные dynamic_cast
или typeid
также не допускаются в постоянных выражениях, так что это нормально.
К сожалению, существует ограничение на подслою, которое может или не имеет значения для вас. Понятие «потенциально оцененное» гораздо более консервативно, чем ограничения того, что применяются постоянные выражения. Таким образом, выше noexcept
может давать ложные отрицания. Он сообщит, что некоторые выражения не являются константными выражениями prvalue, хотя они и есть. Пример:
constexpr int a = (0 ? throw "fooled!" : 42);
constexpr bool atest = isprvalconstexpr((0 ? throw "fooled!" : 42));
В приведенном выше atest
неверно, хотя инициализация a
преуспела. Это потому, что для того, чтобы быть постоянным выражением, достаточно, чтобы «злые» непостоянные подвыражения «никогда не оценивались», хотя эти злые подвыражения являются потенциально оцененными формально.