Попытка реализовать is_constexpr () - компиляторы расходятся - PullRequest
6 голосов
/ 21 мая 2019

Ниже приведены три попытки реализации is_constexpr() на основе Ричарда Смита * ответа на Возможно ли is_constexpr в C ++ 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); }

Я проверял вышеизложенное (см. godbolt ) с 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 |

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

1 Ответ

8 голосов
/ 21 мая 2019

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

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

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

Не имеет значения, что представляют собой две другие марки, поскольку у нас нет предшествующей инициализации в нашем 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.

...