Переменная-член и проверка концепции функции - PullRequest
6 голосов
/ 02 февраля 2020

Я потворствую некоторым ранним воскресным махинациям C ++ 20 и, играя с концепциями ствола gcc / clang, я наткнулся на проблему, для которой не вижу элегантного решения. Рассмотрим этот код:

template <typename T>
concept floating_point = std::is_floating_point_v<std::decay_t<T>>;

template <typename T>
concept indexable = requires(T v)
{
    {v[0]} -> floating_point;
    {v[1]} -> floating_point;
    {v[2]} -> floating_point;
};

template <typename T>
concept func_indexable = requires(T v)
{
    {v.x()} -> floating_point;
    {v.y()} -> floating_point;
    {v.z()} -> floating_point;
};

template <typename T>
concept name_indexable = requires(T v)
{
    {v.x} -> floating_point;
    {v.y} -> floating_point;
    {v.z} -> floating_point;
};

template <typename T>
concept only_name_indexable = name_indexable<T> && !indexable<T>;

template <typename T>
concept only_func_indexable = func_indexable<T> && !indexable<T> && !name_indexable<T>;

void test_indexable(indexable auto v) {
    std::cout << v[0] << " " << v[1] << " " << v[2] << "\n";
}

void test_name_indexable(only_name_indexable auto v) {
    std::cout << v.x << " " << v.y << " " << v.z << "\n";
}

void test_func_indexable(only_func_indexable auto v) {
    std::cout << v.x() << " " << v.y() << " " << v.z() << "\n";
}

(обязательный крестник для игры с этим) https://godbolt.org/z/gyCAQn

Теперь рассмотрим структуру / класс, удовлетворяющий only_func_indexable: Наличие функций-членов x(), y() и z() немедленно приводит к ошибке компиляции в проверке концепции для name_indexable. Точнее:

<source>: In instantiation of 'void test_func_indexable(auto:3) [with auto:3 = func_point]':

<source>:125:26:   required from here

<source>:29:6: error: 'decltype' cannot resolve address of overloaded function

   29 |     {v.x} -> floating_point;

Это довольно очевидно, поскольку .x относится к имени функции-члена, которая является недопустимым выражением внутри decltype. Обратите также внимание на то, что изменение определения name_indexable на

template <typename T>
concept name_indexable = !func_indexable<T> && requires(T v)
{
    {v.x} -> floating_point;
    {v.y} -> floating_point;
    {v.z} -> floating_point;
};

устраняет проблему с помощью оценки ленивых соединений.

Для меня на этом этапе необходимо сказать: «Всякий раз, когда я хочу проверить наличие переменной-члена, которую я имею , чтобы сначала предоставить, и проверить концепцию несуществования функции-члена с таким же именем ".

Теперь это выглядит довольно неловко и похоже на настройка отличных людей в ISO-группы имела более элегантное решение.

Каким будет это решение в этом случае?

Best, Ричард

1 Ответ

0 голосов
/ 02 февраля 2020

Я не уверен, если ваша проблема действительно проблема. Надеемся, что у вас никогда не будет типа, имеющего как элемент данных x, так и функцию-член x, поэтому ваш func_indexable уже равен only_func_indexable, и с этой концепцией проблем не возникнет.

Но если вы хотите быть очень точным, вы можете сделать что-то вроде этого

requires std::is_member_object_pointer_v<decltype(&T::x)> && floating_point<std::invoke_result_t<decltype(&T::x), T>>;

Конечно, это должно быть упаковано в некоторые концепции, а не записываться каждый раз. Обратите внимание, что std::invoke_result_t<decltype(&T::x), T> дает (некоторые ссылки на) float для float x; и float x();.

...