g ++ std :: option кажется, не может поддерживать пользовательский класс с членом переменной std :: atomic / std :: mutex (с деталью / кодом)

Если у меня есть класс с членом std :: atomic_bool или std :: mutex, например, и если я помещу этот класс внутри std :: variant, мой g ++ будет жаловаться на отсутствие соответствующей функции для вызова std :: variant ‹... . ›. Теперь я должен объявить мой член std :: mutex статическим.

g ++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5) Авторские права (C) 2017 Free Software Foundation, Inc. Это бесплатное программное обеспечение; см. источник для условий копирования. Нет никаких гарантий; даже не для КОММЕРЧЕСКОЙ ЦЕННОСТИ или ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ.

Актуальный код

#include <iostream>
#include <variant>
#include <mutex>

enum class enFixEngineRunMode {
    eFixModeStreet      // Fix connection side as initiator/client
    ,eFixModeStreetStandAlone       // Fix connection side as initiator/client
    ,eFixModeStreetAccpt    // Fix connection side as acceptor/server
    ,eFixModeStreetAccptStandAlone  // Fix connection side as acceptor/server
    ,eFixModeClient     // Fix connection side as acceptor/client
    ,eFixModeClientStandAlone       // Fix connection side as acceptor/client
    ,eFixModeClientInit // Fix connection side as initiator/server
    ,eFixModeClientInitStandAlone   // Fix connection side as initiator/server
    ,eFixModeInvalid
};

struct FOO {
    FOO(int any) { }
    void operator()() const {
        std::cout << "FOO2" << std::endl;
    }
};

template <enum enFixEngineRunMode>
struct BAR {
    BAR(double any) { }
    void operator()() const {
        std::cout << "BAR2" << std::endl;
    }

    std::mutex  m_metux;
};

template<>
struct BAR<enFixEngineRunMode::eFixModeStreetStandAlone> {
    BAR(double any) { }
    void operator()() const {
        std::cout << "eFixModeStreetStandAlone" << std::endl;
    }
};

using EngineImpl = std::variant<BAR<enFixEngineRunMode::eFixModeStreet>
                                , BAR<enFixEngineRunMode::eFixModeStreetStandAlone>
                                , BAR<enFixEngineRunMode::eFixModeStreetAccpt>
                                , BAR<enFixEngineRunMode::eFixModeStreetAccptStandAlone>
                                , BAR<enFixEngineRunMode::eFixModeClient>
                                , BAR<enFixEngineRunMode::eFixModeClientStandAlone>
                                , BAR<enFixEngineRunMode::eFixModeClientInit>
                                , BAR<enFixEngineRunMode::eFixModeClientInitStandAlone>
                                , BAR<enFixEngineRunMode::eFixModeInvalid>>;

struct Engine {
    Engine() : m_engine([&] {
        int i = 2;
        if (1 == i)
            return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreetStandAlone>(0.0));
        else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
    }()) {}

    void operator()() const {
        std::visit([](auto const& e){ e(); }, m_engine);
    }
    EngineImpl  m_engine;
};

int main(int argc, const char *argv[], char** env)
{
    Engine e;
    e();
    return 0;
}

ошибка компиляции:

variantMain2.cpp:57:70: error: no matching function for call to ‘std::variant<BAR<(enFixEngineRunMode)0>, BAR<(enFixEngineRunMode)1>, BAR<(enFixEngineRunMode)2>, BAR<(enFixEngineRunMode)3>, BAR<(enFixEngineRunMode)4>, BAR<(enFixEngineRunMode)5>, BAR<(enFixEngineRunMode)6>, BAR<(enFixEngineRunMode)7>, BAR<(enFixEngineRunMode)8> >::variant(BAR<(enFixEngineRunMode)0>)’
   else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
                                                                      ^
In file included from variantMain2.cpp:2:0:
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:986:2: note: candidate: template<long unsigned int _Np, class _Up, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, std::initializer_list<_Up>, _Args&& ...)
  variant(in_place_index_t<_Np>, initializer_list<_Up> __il,
  ^~~~~~~
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:986:2: note:   template argument deduction/substitution failed:
variantMain2.cpp:57:70: note:   ‘BAR<(enFixEngineRunMode)0>’ is not derived from ‘std::in_place_index_t<_Idx>’
   else return EngineImpl(BAR<enFixEngineRunMode::eFixModeStreet>(0.0));
                                                                      ^
In file included from variantMain2.cpp:2:0:
/opt/rh/devtoolset-7/root/usr/include/c++/7/variant:977:2: note: candidate: template<long unsigned int _Np, class ... _Args, class> constexpr std::variant<_Types>::variant(std::in_place_index_t<_Np>, _Args&& ...)
  variant(in_place_index_t<_Np>, _Args&&... __args)


person MingC    schedule 23.11.2020    source источник
comment
Какой здесь вопрос? Правильно ли GCC отклонить этот код? Если да, то почему это недействительно? Как избежать проблемы без static?   -  person Davis Herring    schedule 23.11.2020
comment
возможно Q1 - GCC правильный, не может быть и речи. Но почему CC к gcc-help - это любые советы экспертной группы. Q2 - почему недействителен и как избежать проблемы без статики. Да, это то, что я хотел бы услышать.   -  person MingC    schedule 24.11.2020
comment
Конструктор выбранного варианта пытается переместить или скопировать из своего аргумента. Вы не можете сделать то же самое с мьютексом. Вместо этого вы можете установить вариант (en.cppreference.com/w/cpp/ полезность / вариант / место)   -  person user2407038    schedule 24.11.2020


Ответы (1)


Поскольку std::variant не является агрегатом, он должен перемещать свои аргументы во внутреннюю память, а std::mutex не может перемещаться (поскольку это нарушит работу любых одновременно работающих пользователей). Вы можете сделать BAR перемещаемым (например, сохранив std::unique_ptr<std::mutex>) или избежать перемещения, используя std::in_place_type для создания объекта внутри вариант.

person Davis Herring    schedule 24.11.2020
comment
Я пробовал std :: in_place_type. может не правильно. Я уверен, что попробую и дальше. - person MingC; 24.11.2020