Разница в предоставлении двух вариантов объектов по отдельности и в массиве

У меня есть два варианта объектов следующего типа

struct FigureMove {};
struct PieceMove {};
using Move = std::variant<FigureMove, PieceMove>;

Я хочу предоставить два объекта Move функции и вызывать разные функции в зависимости от базовых типов в вариантах. У меня есть две разные версии функции, которая принимает объекты Move. Один принимает их как отдельные аргументы функции, а другой принимает их оба в array. Обратите внимание, я планирую поставлять всегда один FigureMove и один PieceMove, просто их порядок заранее не ясен.

bool areMovesValid(const FigureMove &figureMove0, const PieceMove &pieceMove1)
{
    return {};
}

bool areMovesValid(const PieceMove &pieceMove0, const FigureMove &figureMove1)
{
    return {};
}

//#define USE_ARRAY

#ifdef USE_ARRAY
bool areMovesValid(const std::array<Move, 2> &moves)
{
    const auto &variantMove0 = moves[0];
    const auto &variantMove1 = moves[1];

#else
bool areMovesValid(const Move &variantMove0, const Move &variantMove1)
{
#endif
    return std::visit(
        [variantMove1](const auto move0)
        {
            return std::visit(
                [move0](const auto move1)
                {
                    return areMovesValid(move0, move1);
                },
                variantMove1);
        },
        variantMove0);
}

Версия с array выдает массу ошибок времени компиляции. Использование gcc или clang.

Почему это так и как я могу это исправить?

Вот код на godbolt.

К вашему сведению, std::visit поддерживает более одного варианта одновременно. Вы можете сделать один вызов с обоими вариантами для отправки, используя оба аргумента одновременно.

chris 19.02.2023 15:23
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы
HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!
Современный фронтенд похож на старую добрую веб-разработку, но с одной загвоздкой: страница в браузере так же сложна, как и бэкенд.
Узнайте, как использовать теги &lt;ul&gt; и &lt;li&gt; для создания неупорядоченных списков в HTML
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
HTML предоставляет множество тегов для структурирования и организации содержимого веб-страницы. Одним из наиболее часто используемых тегов для...
2
1
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
return areMovesValid(move0, move1);

Если параметр массива не используется, это приводит к бесконечной рекурсии для комбинации двух значений одного типа, поскольку разрешение перегрузки будет выбирать одно и то же areMovesValid.

При использовании версии параметра массива: разрешение перегрузки не выполняется, так как эти два параметра нельзя преобразовать в один std::array, а остальные перегрузки не совпадают.

Если вы решите назвать третью функцию, которая принимает пару Move как что-то отличное от areMovesValid, ни одна из версий не будет скомпилирована.

Я планирую всегда поставлять один FigureMove и один PieceMove

Это хорошо, но ваш компилятор C++ не верит вам на слово. Комбинация двух вызовов std::visit также будет генерировать пути кода, где оба параметра являются как FigureMoves, так и PieceMoves. И это должно как-то компилироваться.

Затем мне нужно написать функции, принимающие (FigureMove, FigureMove) и (PieceMove, PieceMove), и они должны нормально компилироваться? Попробую.

jack 19.02.2023 15:26

Да, должно компилироваться.

Sam Varshavchik 19.02.2023 15:27

Следуя объяснению @SamVarshavchik и вкладу @chris, я придумал это решение:

// additional headers
#include <stdexcept>
#include <type_traits>

// previous code

// changes made to dispatching function
bool areMovesValid(const std::array<Move, 2> &moves)
{
    return std::visit(
        []<typename Move0, typename Move1>(Move0 move0, Move1 move1) -> bool
        {
            if constexpr (std::is_same_v<Move0, Move1>)
                throw std::invalid_argument("unsupported arguments!");
            else
                return areMovesValid(move0, move1);
        },
        moves[0], moves[1]);
}

Изменение заключается в том, что для тех же базовых типов в варианте Move мы выбрасываем исключение. Кроме того, мы отправляем через один std::visit.

Другие вопросы по теме