g++ std::variant 似乎无法支持用户 class 与 std::atomic/std::mutex 变量成员(与 detail/code)
g++ std::variant seems can't support user class with std::atomic/std::mutex variable member (with detail/code)
例如,如果我有一个带有 std::atomic_bool 或 std::mutex 成员的 class,并且如果我将这个 class 放在 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)
因为std::variant
不是聚合,它必须将它的参数移动到它的内部存储中,而std::mutex
是不可移动的(因为这样做会打破任何并发用户)。您的选择是 BAR
可移动 ( 例如 ,通过存储 std::unique_ptr<std::mutex>
),或者避免移动使用 std::in_place_type
在 变体中构造对象 。
例如,如果我有一个带有 std::atomic_bool 或 std::mutex 成员的 class,并且如果我将这个 class 放在 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)
因为std::variant
不是聚合,它必须将它的参数移动到它的内部存储中,而std::mutex
是不可移动的(因为这样做会打破任何并发用户)。您的选择是 BAR
可移动 ( 例如 ,通过存储 std::unique_ptr<std::mutex>
),或者避免移动使用 std::in_place_type
在 变体中构造对象 。