在C ++ 17中,我实现了玩具vm。我使用std :: variant()作为VM堆栈的元素。我需要将字符串压入堆栈,代表不同类型的操作数,即:
所有3种类型的操作数都可以是std :: string_view类型。变体的定义如下:
enum StringKind { Symbol, String, Var };
using Stringy = std::tuple<StringKind, std::string_view>; // SV can be symbol, var, string
std::variant<bool, int, double, Stringy>;
为了区分字符串视图的实际类型,是否有正确的方法来做这样的事情?
app.post('/login', function(req, res, next){
passport.authenticate('local', (err, user, info),{
if(err) {
return res.send({err: err, info:info});
}
res.send(user);
})(req, res, next);
});
或者可以在变体上编码字符串种类。在变体级别执行此操作的一个好处是可以通过调用std :: variant :: index()来获得类型。否则,我必须检查.index()== 3,std :: get&lt; 3&gt;(var),然后检查类型以查看其字符串,符号或变量。
答案 0 :(得分:0)
我刚试过这个,我喜欢它:
enum StackStringType {};
enum StackSymbolType {}
enum StackVarType {};
using StackString = std::tuple<StackStringType, std::string_view>;
using StackSymbol = std::tuple<StackSymbolType, std::string_view>;
using StackVar = std::tuple<StackVarType, std::string_view>;
using StackType = std::variant<bool, StackString, StackSymbol, StackVar>;
答案 1 :(得分:0)
另一种方法是创建一个模板化的类来“标记”各种枚举类型。这样就不需要为每个枚举值设置一个“using”语句,这样你就可以重复一遍了。
enum class StringKind { Symbol, String, Var };
template <StringKind T> struct TaggedString { std::string_view value; };
using StackType = std::variant<bool,
int,
double,
TaggedString<StringKind::Symbol>,
TaggedString<StringKind::String>,
TaggedString<StringKind::Var>>;
另外,您提到使用std::variant::index()
来获取变体中包含的类型。另一种方法是使用std::visit()
以下列方式更安全:
#include <iostream>
#include <string_view>
#include <variant>
template<typename T> struct always_false : std::false_type { };
enum class StringKind { Symbol, String, Var };
template <StringKind T> struct TaggedString { std::string_view value; };
using StackType = std::variant<bool,
int,
double,
TaggedString<StringKind::Symbol>,
TaggedString<StringKind::String>,
TaggedString<StringKind::Var>>;
std::ostream& operator<<(std::ostream& stream, const StackType& st) {
std::visit([&stream](auto&& var) {
using T = std::decay_t<decltype(var)>;
if constexpr (std::is_same_v<T, bool>) {
stream << "Bool(" << var << ")";
} else if constexpr (std::is_same_v<T, int>) {
stream << "Int(" << var << ")";
} else if constexpr (std::is_same_v<T, double>) {
stream << "Double(" << var << ")";
} else if constexpr (std::is_same_v<T, TaggedString<StringKind::Symbol>>) {
stream << "Symbol(" << var.value << ")";
} else if constexpr (std::is_same_v<T, TaggedString<StringKind::String>>) {
stream << "String(" << var.value << ")";
} else if constexpr (std::is_same_v<T, TaggedString<StringKind::Var>>) {
stream << "Var(" << var.value << ")";
} else {
static_assert(always_false<T>::value, "non-exhaustive visitor!");
}
}, st);
return stream;
}
int main(int, char**) {
StackType t_bool = true;
StackType t_int = 3;
StackType t_double = 3.0;
StackType t_symbol = TaggedString<StringKind::Symbol>{"Foo"};
StackType t_string = TaggedString<StringKind::String>{"Bar"};
StackType t_var = TaggedString<StringKind::Var>{"Baz"};
std::cout << t_bool << std::endl
<< t_int << std::endl
<< t_double << std::endl
<< t_symbol << std::endl
<< t_string << std::endl
<< t_var << std::endl;
}
该程序输出:
Bool(1)
Int(3)
Double(3)
Symbol(Foo)
String(Bar)
Var(Baz)
答案 2 :(得分:0)
这个怎么样?
struct StackString : std::string_view {};
struct StackSymbol : std::string_view {};
struct StackVar : std::string_view {};
using StackType = std::variant<bool, int, double, StackString, StackSymbol, StackVar>;