Как передать вариант в качестве параметра конструктора или аргумента функции - PullRequest
2 голосов
/ 22 июня 2019

Я читаю о реализации конечных автоматов с использованием вариантов. Я пытаюсь создать конструкцию, которая принимает вариант параметра для инициализации состояния. Как бы ни был определен конструктор, я получаю предупреждение, что это распознается как объявление функции.

Более того, когда я пытаюсь определить установщик для состояния, генерируется ошибка компилятора при попытке вызвать это

Вот код

#include "pch.h"
#include <iostream>
#include <variant>
#include <cassert>

struct DoorState
{
    struct DoorOpened {};
    struct DoorClosed {};
    struct DoorLocked {};

    using State = std::variant<DoorOpened, DoorClosed, DoorLocked>;
    DoorState()
    {
    }
    DoorState(State & state)
    {
        m_state = state;
    }
    void open()
    {
        m_state = std::visit(OpenEvent{}, m_state);
    }

    void close()
    {
        m_state = std::visit(CloseEvent{}, m_state);
    }

    void lock()
    {
        m_state = std::visit(LockEvent{}, m_state);
    }

    void unlock()
    {
        m_state = std::visit(UnlockEvent{}, m_state);
    }

    struct OpenEvent
    {
        State operator()(const DoorOpened&) { return DoorOpened(); }
        State operator()(const DoorClosed&) { return DoorOpened(); }
        // cannot open locked doors
        State operator()(const DoorLocked&) { return DoorLocked(); }
    };

    struct CloseEvent
    {
        State operator()(const DoorOpened&) { return DoorClosed(); }
        State operator()(const DoorClosed&) { return DoorClosed(); }
        State operator()(const DoorLocked&) { return DoorLocked(); }
    };

    struct LockEvent
    {
        // cannot lock opened doors
        State operator()(const DoorOpened&) 
        { 
            std::cout << "DoorOpened" << std::endl;
            return DoorOpened(); 
        }
        State operator()(const DoorClosed&) { return DoorLocked(); }
        State operator()(const DoorLocked&) { return DoorLocked(); }
    };

    struct UnlockEvent
    {
        // cannot unlock opened doors
        State operator()(const DoorOpened&) { return DoorOpened(); }
        State operator()(const DoorClosed&) { return DoorClosed(); }
        // unlock
        State operator()(const DoorLocked&) { return DoorClosed(); }
    };
    void set(State state)
    {
    }
    State m_state;
};

int main()
{
    //DoorState s(DoorState::DoorOpened);
    DoorState s; 
    s.set(DoorState::DoorOpened);
    s.lock();
    return 0;
}

1 Ответ

2 голосов
/ 22 июня 2019

В

s.set(DoorState::DoorOpened);

вы передаете тип, вы должны передать экземпляр типа, попробуйте

s.set(DoorState::DoorOpened{});

после этого изменения я смог скомпилировать в MSVC 2019 (16.1.3)

Редактировать: это редактирование адресов комментариев к Шеффу и Jarod24, если бы мы раскомментировали конструктор и написали

DoorState s(DoorState::DoorOpened());
* 1011, был бы самый неприятный анализ* Это могло быть исправлено с использованием единого синтаксиса инициализации, см., Например, https://arne -mertz.de / 2015/07 / new-c-features -iform-initial-initialization-and-initializer_list /
DoorState s{DoorState::DoorOpened{}};

Это решило бы самую неприятную проблему разбора, но создало бы новую проблему: DoorState::DoorOpened{} было бы временным и никогда не могло быть связано с входным аргументом ctor:

DoorState(State& state)

тогда нам нужно было бы изменить его на

DoorState(const State& state)

Еще раз спасибо Джароду и Шеффу за указание на проблему.

...