Может ли концепция потребовать значение или функцию constexpr? - PullRequest
0 голосов
/ 16 мая 2018

Итак, я хотел бы сделать несколько продвинутых хакеров на уровне типов, для которых мне бы очень хотелось написать концепцию, требующую, чтобы тип имел ассоциированное с ним значение constexpr int, которое я смогу использовать позже.в той же концепции, что и целочисленный std::array параметр шаблона.

Можно написать

template<typename T>
concept bool HasCount = requires {
    typename T::count;
};

, но это не то, что я хочу;Я бы хотел, чтобы T::count был static constexpr int.Однако код (даже не включая необходимый constexpr)

template<typename T>
concept bool HasCount = requires {
    int T::count;
};

не компилируется с «error: ожидаемое первичное выражение перед« int »» в GCC 7.3.0.

Еще одна неудачная попытка: можно написать это, что потребует static int T::count():

template<typename T>
concept bool HasCount = requires {
    {T::count()} -> int;
};

, но не этого, чего я хочу:

template<typename T>
concept bool HasCount = requires {
    {T::count()} -> constexpr int;
    {T::count() constexpr} -> int; // or this
    {constexpr T::count()} -> int; // or this (please forgive me for fuzzing GCC instead of reading the manual, unlike perl C++ is not an empirical science)
};

Итак, я 'Хотелось бы знать, возможно ли каким-либо образом требовать, чтобы выражение понятия было квалифицировано constexpr, или нет, если есть причина, по которой это невозможно, или просто не включено в спецификацию.

1 Ответ

0 голосов
/ 16 мая 2018

Теоретически это возможно, требуя, чтобы T::count было допустимым выражением, и требуя, чтобы допустимо использовать T::count в контексте, который требует константного выражения. Например:

#include <type_traits>
#include <utility>

template<int> using helper = void;

template<typename T>
concept bool HasCount = requires {
    // T::count must be a valid expression
    T::count;
    // T::count must have type int const
    requires std::is_same_v<int const, decltype(T::count)>;
    // T::count must be usable in a context that requires a constant expression
    typename ::helper<T::count>;
};

struct S1 {
    static constexpr int count = 42;
};
static_assert(HasCount<S1>);

struct S2 {
    int count = 42;
};
static_assert(!HasCount<S2>);

struct S3 {
    static constexpr double count = 3.14;
};
static_assert(!HasCount<S3>);

но на практике реализация концепций в GCC отвергает эту программу :

<source>:20:16: error: invalid use of non-static data member 'S2::count'
 static_assert(!HasCount<S2>);
                ^~~~~~~~~~~~
<source>:18:17: note: declared here
     int count = 42;
                 ^~
<source>:20:16: error: invalid use of non-static data member 'S2::count'
 static_assert(!HasCount<S2>);
                ^~~~~~~~~~~~
<source>:18:17: note: declared here
     int count = 42;
                 ^~

(какой факт Я считаю ошибкой .)

...