Попытка реализации is_constexpr() — расходятся компиляторы

Ниже приведены три попытки реализовать is_constexpr() на основе отвечатьРичард Смит до Возможен ли is_constexpr в С++ 11?.

Версия 1

template <typename T>
bool constexpr is_constexpr_impl_1(const T& x, decltype(int{(x, 0u)})) { return true; }

template <typename T>
bool constexpr is_constexpr_impl_1(const T&, ...) { return false; }

template <typename T>
bool constexpr is_constexpr_1(const T& x) { return is_constexpr_impl_1(x, 0); }

Версия 2

template <typename T>
bool constexpr is_constexpr_impl_2(const T& f, decltype(int{(f(0), 0u)})) { return true; }

template <typename T>
bool constexpr is_constexpr_impl_2(const T&, ...) { return false; }

template <typename T>
bool constexpr is_constexpr_2(const T& f) { return is_constexpr_impl_2(f, 0); }

Версия 3

template <auto f>
bool constexpr is_constexpr_impl_3(decltype(int{(f(0), 0u)})) { return true; }

template <auto f>
bool constexpr is_constexpr_impl_3(...) { return false; }

template <auto f>
bool constexpr is_constexpr_3() { return is_constexpr_impl_3<f>(0); }

Я протестировал вышеизложенное (см. божественная стрела) с gcc 9.1, clang 8.0.0, icc 19.0.1 и msvc 19.20 и помощью следующих функций:

void constexpr f_c(int) {}
void f_nc(int) {}

В таблице ниже показаны выражения, которые я поставил в static_assert. Я бы ожидал, что все они пройдут, но компиляторы не согласны со мной и между собой (кроме icc и msvc, которые согласуются друг с другом):

                        | gcc  | clang | icc  | msvc |
 is_constexpr_1(0)      | pass | fail  | pass | pass |
 is_constexpr_2(f_c)    | fail | fail  | pass | pass |
!is_constexpr_2(f_nc)   | pass | pass  | fail | fail |
 is_constexpr_3<f_c>()  | pass | pass  | pass | pass |
!is_constexpr_3<f_nc>() | pass | pass  | fail | fail |

Кто прав и почему? (Цитаты из Стандарта были бы полезны.)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
219
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ни is_constexpr_1, ни is_constexpr_2 недействительны, потому что они противоречат обычному правилу, согласно которому параметры функции нельзя использовать в константных выражениях. Они требуют, чтобы x и f, соответственно, хотя бы иногда можно было использовать в качестве постоянного выражения, а это никогда не так.

В этом случае ограничение [expr.const]/4:

an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either [...]

Неважно, какие две другие пули, так как у нас нет предшествующей инициализации в нашей id-выражение, которая ссылается на переменную.

is_constexpr_3 действителен, как объясняет Ричард Смит в связанный ответ.

Мои ожидания:

                        | 
 is_constexpr_1(0)      | fail
 is_constexpr_2(f_c)    | fail
!is_constexpr_2(f_nc)   | pass
 is_constexpr_3<f_c>()  | pass
!is_constexpr_3<f_nc>() | pass

что делает clang.

Другие вопросы по теме