Я потворствую некоторым ранним воскресным махинациям 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, Ричард