Замысловатые правила оператора<=> в случае взаимно рекурсивного std::variantC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Замысловатые правила оператора<=> в случае взаимно рекурсивного std::variant

Сообщение Anonymous »

Исходя из C++17 и пытаясь интегрировать оператор. Я наткнулся на загадку. Кажется, не существует способа реализовать универсальный класс, подобный контейнеру, где его T является взаимно рекурсивным std::variant. С обычным набором операторов сравнения до C++20 все в порядке, вероятно, потому, что они полностью определены в любой момент времени. Событие, если T заранее объявлено в точке объявления шаблона.
Я собрал упрощенный набор тестовых примеров, которые делают эту проблему очевидной. Здесь Array и Map не являются шаблонными, а представляют собой простые структуры, для простоты основанные на std::vector и std::map. Это по-прежнему ясно показывает, что тип категории сравнения должен быть известен заранее. Или оператор придется вообще исключить, но есть недостатки (доступно на godbolt.com).

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 

/// Set 1-8, to choose between cases
#define CASE 1
#define WANT_DEFAULT_WHEN_MEMEBER 0

/// Must be forward declared, as, e.g., using `std::vector` in Var's declaration would not be possible
struct Array;
struct Map;

using Var = std::variant;

/// [CASE 1] Deduced comparison category type + default
/// [COMPILES] No compiler
#if CASE == 1

struct Array
{
bool operator==(const Array & that) const = default;
auto operator(const Array & that) const = default;

std::vector value;
};

struct Map
{
bool operator==(const Map & that) const = default;
auto operator(const Map & that) const = default;

std::map value;
};

/// [CASE 2] Deduced comparison category type, declared outside, still default
/// [COMPILES] No compiler
#elif CASE == 2

struct Array
{
bool operator==(const Array & that) const = default;
auto operator(const Array & that) const;

std::vector value;
};

struct Map
{
bool operator==(const Map & that) const = default;
auto operator(const Map & that) const;

std::map value;
};

auto Array::operator(const Array & that) const = default;

auto Map::operator(const Map & that) const = default;

/// [CASE 3] Declared outside, with concrete comparison category type
/// [COMPILES] Only in GCC 15.2
#elif CASE == 3

struct Array
{
bool operator==(const Array & that) const = default;
std::weak_ordering operator(const Array & that) const;

std::vector value;
};

struct Map
{
bool operator==(const Map & that) const = default;
std::weak_ordering operator(const Map & that) const;

std::map value;
};

std::weak_ordering Array::operator(const Array & that) const
{
return value  that.value;
}

std::weak_ordering Map::operator(const Map & that) const
{
return value  that.value;
}

/// [CASE 4] Template hack to delay instantiation, deduced comparison category type
/// [COMPILES] Only MSVC 19
#elif CASE == 4

struct Array
{
bool operator==(const Array & that) const;
template 
auto operator(const T & that) const;

std::vector value;
};

struct Map
{
bool operator==(const Map & that) const;
template 
auto operator(const T & that) const;

std::map value;
};

template 
auto Array::operator(const T & that) const
{
return value  that.value;
}

template 
auto Map::operator(const T & that) const
{
return value  that.value;
}

bool Array::operator==(const Array & that) const
{
return value == that.value;
}

bool Map::operator==(const Map & that) const
{
return value == that.value;
}

/// [CASE 5] Template hack to delay instantiation, concrete comparison category type
/// [COMPILES] All compilers
/// [LIMITATION] Requires knowing comparison category type, won't work if deducation is needed (template class)
#elif CASE == 5

struct Array
{
bool operator==(const Array & that) const;
template 
std::weak_ordering operator(const T & that) const;

std::vector value;
};

struct Map
{
bool operator==(const Map & that) const;
template 
std::weak_ordering operator(const T & that) const;

std::map  value;
};

template 
std::weak_ordering Array::operator(const T & that) const
{
return value  that.value;
}

template 
std::weak_ordering Map::operator(const T & that) const
{
return value  that.value;
}

bool Array::operator==(const Array & that) const
{
return value == that.value;
}

bool Map::operator==(const Map & that) const
{
return value == that.value;
}

/// [CASE 6] As friends, no template hacks, declared before the type is defined
/// [COMPILES] Only MSVC 19
/// [LIMITATION] Only as out of class friend (not critical)
#elif CASE == 6

struct Array
{
friend bool operator==(const Array & _1, const Array & _2);
friend auto operator(const Array & _1, const Array & _2);

std::vector value;
};

struct Map
{
friend bool operator==(const Map & _1, const Map & _2);
friend auto operator(const Map & _1, const Map & _2);

std::map value;
};

bool operator==(const Array & _1, const Array & _2)
{
return _1.value == _2.value;
}

auto operator(const Array & _1, const Array & _2)
{
return _1.value  _2.value;
}

bool operator==(const Map & _1, const Map & _2)
{
return _1.value == _2.value;
}

auto operator(const Map & _1, const Map & _2)
{
return _1.value  _2.value;
}

/// [CASE 7] As friends, no template hacks, declared before the type is defined, concrete comparison category type
/// [COMPILES] Only MSVC 19
/// [LIMITATION] Only as out of class friend (not critical)
/// [LIMITATION] Requires knowing comparison category type, won't work if deducation is needed (template class)
#elif CASE == 7

struct Array
{
friend bool operator==(const Array & _1, const Array & _2);
friend std::weak_ordering operator(const Array & _1, const Array & _2);

std::vector value;
};

struct Map
{
friend bool operator==(const Map & _1, const Map & _2);
friend std::weak_ordering operator(const Map & _1, const Map & _2);

std::map value;
};

bool operator==(const Array & _1, const Array & _2)
{
return _1.value == _2.value;
}

std::weak_ordering operator(const Array & _1, const Array & _2)
{
return _1.value  _2.value;
}

bool operator==(const Map & _1, const Map & _2)
{
return _1.value == _2.value;
}

std::weak_ordering operator(const Map & _1, const Map & _2)
{
return _1.value  _2.value;
}

/// [CASE 8] The full set of operators (pre C++20 way)
/// [COMPILES] All compilers
/// [LIMITATION] No `` therefore, when contained by another class, that class can't default its ``,
///              at least in clang, but others seem incorrect as there is no way to deduce comparison category type
///              I.e.  won't work with `WANT_DEFAULT_WHEN_MEMEBER == 1`
#elif CASE == 8

struct Array
{
/// Can't be defaulted: some type would be forward declared at that point.
bool operator==(const Array & that) const;
bool operator

Подробнее здесь: [url]https://stackoverflow.com/questions/79896261/convoluted-operator-rules-in-case-of-mutually-recursive-stdvariant[/url]
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»