【问题标题】:g++ std::variant seems can't support user class with std::atomic/std::mutex variable member (with detail/code)g++ std::variant 似乎不支持带有 std::atomic/std::mutex 变量成员的用户类(带有详细信息/代码)
【发布时间】:2021-03-06 03:31:33
【问题描述】:

例如,如果我有一个带有 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)

【问题讨论】:

  • 这里的问题是什么? GCC拒绝此代码是否正确?如果是这样,为什么它是无效的?没有static如何避免这个问题?
  • 可能的 Q1 -- GCC 正确是不可能的。但是为什么CC到gcc-help是看专家组的意见。 Q2 - 为什么无效以及如何避免没有静态的问题。是的,这就是我想听到的。
  • 被选择的变体的构造函数尝试从其参数中移动或复制。你不能用互斥锁做任何一个。相反,您可以使用变体 (en.cppreference.com/w/cpp/utility/variant/emplace)

标签: c++ c++17 stdatomic std-variant


【解决方案1】:

因为std::variant 不是聚合,它必须将其参数移动 到其内部存储中,并且std::mutex 不可移动(因为这样做会破坏任何并发用户)。您的选择是使BAR 可移动例如,通过存储std::unique_ptr&lt;std::mutex&gt;),或者通过使用std::in_place_type 构造对象来避免移动内部变体。

【讨论】:

  • 我试过 std::in_place_type。也许不正确。我有信心进一步尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 2021-05-17
  • 1970-01-01
  • 2020-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多