我试图创建一个std :: variant,它可以包含相同变量的向量:
class ScriptParameter;
using ScriptParameter = std::variant<bool, int, double, std::string, std::vector<ScriptParameter> >;
Run Code Online (Sandbox Code Playgroud)
我正在重新定义ScriptParameter.它认为可能是因为模板参数无法向前声明?
有没有办法实现一个也可以包含相同类型变体数组的变体?
使用 C++14,我将其boost::variant用作编译时多态性的一种方式:
using MyType = boost::variant<A, B>;
Run Code Online (Sandbox Code Playgroud)
这两个类都有一个方法sayHello()。我想打电话给:
MyType obj = ...; // either A() or B()
boost::visit([](auto&& o) { o.sayHello();}, obj);
Run Code Online (Sandbox Code Playgroud)
我知道static_visitor方法,但我觉得它很麻烦。有没有boost::visit像std::visit我失踪?如果没有,为什么它不存在?
最小的例子在这里。
下面的代码
#include <optional>
#include <string>
#include <variant>
constexpr bool USE_VARIANT = 1;
using T = std::conditional_t<USE_VARIANT, std::variant<std::string>, std::string>;
struct S
{
T t;
};
constexpr int func()
{
S s{"str"};
return 0;
}
constexpr int x = func();
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
无法使用 GCC trunk(编译器资源管理器链接)进行编译,并显示以下消息
In file included from <source>:4:
<source>:21:23: in 'constexpr' expansion of 'func()'
<source>:19:1: in 'constexpr' expansion of '(& s)->S::~S()'
<source>:10:8: in 'constexpr' expansion of '((S*)this)->S::t.std::variant<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::~variant()'
/opt/compiler-explorer/gcc-trunk-20211231/include/c++/12.0.0/variant:1408:28: in 'constexpr' expansion of '((std::variant<std::__cxx11::basic_string<char, …Run Code Online (Sandbox Code Playgroud) 这是示例代码:http://coliru.stacked-crooked.com/a/5f630d2d65cd983e
#include <variant>
#include <functional>
template<class... Ts> struct overloads : Ts... { using Ts::operator()...; };
template<class... Ts> overloads(Ts &&...) -> overloads<std::remove_cvref_t<Ts>...>;
template<typename... Ts, typename... Fs>
constexpr inline auto transform(const std::variant<Ts...> &var, Fs &&... fs)
-> decltype(auto) { return std::visit(overloads{fs...}, var); }
template<typename... Ts, typename... Fs>
constexpr inline auto transform_by_ref(const std::variant<Ts...> &var, Fs &&... fs)
-> decltype(auto) { return std::visit(overloads{std::ref(fs)...}, var); }
int main()
{
transform(
std::variant<int, double>{1.0},
[](int) { return 1; },
[](double) { return 2; }); // fine …Run Code Online (Sandbox Code Playgroud) std::variant我已经知道如何很好地使用std::get_if(),std::get()和std::visit()。但是,如果我只是想要一种简单的方法来判断变体是否已初始化为任何值怎么办?也就是说,我不在乎值是什么,我只想要一个布尔测试。我怎么做?
例如,假设我在堆栈上声明一个变体:
std::variant<int, double> data;
Run Code Online (Sandbox Code Playgroud)
然后,我的函数继续运行,可能会也可能不会初始化该变量。在函数结束时,我想测试它是否已初始化。
index()函数。对于未初始化的变体和我初始化为声明的第一个类型的变体都返回 0 。valueless_by_exception()函数,但无论我是否初始化变体,它都会返回 false。我唯一能想到的是将它与默认构造的进行比较,如下所示:
using Data = std::variant<int, double>;
Data data;
// ... code here that might initialize data or might not...
if (data == Data())
// Not initialized
else
// Initialized
Run Code Online (Sandbox Code Playgroud)
这似乎有效,但阅读for的评论operator==()std::variant,似乎这种行为是未定义的。
那么,这是一种安全的测试方法,还是还有其他方法?
例如,我尝试使用 实现 AST std::variant,其中 Token 可以是数字、关键字或变量。其中数字由 表示int,关键字和变量由 表示std::string:
enum TokenType : std::size_t {
Number = 0, Keyword = 1, Variable = 2,
};
using Token = std::variant<int, std::string, std::string>;
Token token(std::in_place_index<TokenType::Variable>, "x");
Run Code Online (Sandbox Code Playgroud)
当我想用 做某事时token,我可以首先确定它的类型token.index(),然后决定要做什么:
switch (token.index()) {
case TokenType::Number:
return do_sth_with_number(std::get<TokenType::Number>(token));
case TokenType::Keyword:
return do_sth_with_keyword(std::get<TokenType::Keyword>(token));
case TokenType::Variable:
return do_sth_with_variable(std::get<TokenType::Variable>(token));
}
Run Code Online (Sandbox Code Playgroud)
不过,我不知道是否可以使用它std::visit来达到同样的效果。我只知道它可以根据变体中的数据类型调用特定函数,但我不知道是否可以根据索引来执行此操作。
我知道我可以通过将关键字和变量包装在两个不同的类中来实现我的目标,但我想知道是否有更好的方法来做到这一点,因为据我了解,在变体中,决定使用哪个函数应该更直接基于索引而不是类型使用。
我想要一个可能包含类型Foo,(不相交)类型Bar的变体,或者什么都没有.好吧,当然,我正在考虑使用std::variant<Foo, Bar, void>- 但这似乎不起作用.也就是说,您可以定义此类型,但如果您尝试实例化它,则会失败(GCC 8.2).
那我该用什么呢?某种空结构?
使用以下代码如何正确编写自定义模板推导?
template<class R, class State, class... Ts> struct visitor : Ts... { using Ts::operator()...; };
template<class R, class State, class... Ts> visitor(State, Ts...)->visitor<class R, State,Ts...>;
using Event = std::variant<HeartBeat, ConfigurationRead>;
using State = std::variant<Idle, Starting, Running, Error>;
void case3()
{
Event e;
State currentState;
State newState = std::visit( visitor{
[](Idle&& state, HeartBeat event) {std::cout << "Currently stopped, heartbeat received.\n"; return Error{}; }
}, currentState, e);
}
Run Code Online (Sandbox Code Playgroud)
我已经看了几个例子,但我找不到一个使用std :: visit的返回.
考虑:
#include <variant>
struct A {
A() = default;
A(A&&) = delete;
};
struct B {
B() = delete;
B(A&&) {};
};
int main() {
std::variant<A, B> v{};
v = A{};
}
Run Code Online (Sandbox Code Playgroud)
MSVC 接受了它,而 GCC 和 Clang 以相同的错误消息拒绝了它:
opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/12.0.0/../../../../include/c++/12.0.0/variant:1465:3: error: call to deleted member function 'operator='
operator=(variant(std::forward<_Tp>(__rhs)));
^~~~~~~~~
<source>:15:5: note: in instantiation of function template specialization 'std::variant<A, B>::operator=<A>' requested here
v = A{};
^
Run Code Online (Sandbox Code Playgroud)
我应该信任哪个编译器?
我有两个结构A1,A2另一个结构B有两个结构的构造函数。如何编写 的委托构造函数std::variant<A1,A2>?
#include <variant>
struct A1 {};
struct A2 {};
using A = std::variant<A1, A2>;
struct B {
B(const A1 &){}
B(const A2 &){}
B(const A& a)
:B(a) // <--- what do I put here to delegate like std::visit ?
{}
};
int main(int argc, char *argv[]) {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在寻找一种本着 的精神的干净的现代方式std::visit。B我知道我可以使用静态成员函数通过Ausing和 lambda构造实例std::visit,但这不是我所要求的,因为我想依赖从A到 的隐式类型转换B。