我正在尝试提出一种解析字符串的通用解决方案(使用给定的格式)。例如,我希望能够解析包含数值列表(整数或浮点数)的字符串并返回一个std :: vector。这就是我到目前为止所做的:
template<typename T, typename U>
T parse_value(const U& u) {
throw std::runtime_error("no parser available");
}
template<typename T>
std::vector<T> parse_value(const std::string& s) {
std::vector<std::string> parts;
boost::split(parts, s, boost::is_any_of(","));
std::vector<T> res;
std::transform(parts.begin(), parts.end(), std::back_inserter(res),
[](const std::string& s) { return boost::lexical_cast<T>(s); });
return res;
}
此外,我希望能够解析包含其他类型值的字符串。例如:
struct Foo { /* ... */ };
template<>
Foo parse_value(const std::string& s) {
/* parse string and return a Foo object */
}
维护parse_value
函数的单个“层次结构”的原因是,有时,我想使用boost :: optional来解析可选值(可能存在或不存在)。理想情况下,我希望只有一个parse_optional_value
函数可以委托相应的parse_value
函数:
template<typename T>
boost::optional<T> parse_optional_value(const boost::optional<std::string>& s) {
if (!s) return boost::optional<T>();
return boost::optional<T>(parse_value<T>(*s));
}
到目前为止,我当前的解决方案不起作用(编译器无法推断出要使用的确切函数)。我想问题是我的解决方案依赖于根据parse_value
函数的返回类型推导出模板值。我不确定如何解决这个问题(甚至是否可以修复它,因为设计方法可能完全有缺陷)。有谁知道解决我想做的事情的方法?如果您能指出一种可能的方法来解决我当前实施中遇到的问题,我将非常感激。顺便说一下,我对解决这个问题的想法完全不同。
答案 0 :(得分:1)
您不能根据返回值[1]重载函数。这正是标准IO库使用构造的原因:
std::cin >> a >> b;
这可能不是你的小蛋糕 - 许多人不喜欢它,它确实不是没有它的问题 - 但它为解析器提供目标类型做得很好。如上所述,它还具有优于静态parse<X>(const std::string&)
原型的优势,它允许链接和流式传输。有时这不是必需的,但在许多解析上下文中它是必不可少的,使用operator>>
实际上是一个非常酷的语法。 [2]
标准库不会做最远和最酷的事情,即跳过字符串常量scanf
样式并允许交错读取。
vector<int> integers;
std::cin >> "[" >> interleave(integers, ",") >> "]";
然而,可以定义。 (可能最好在字符串文字周围使用一个显式的包装器,但实际上我更喜欢它;但如果你传递一个变量你想要使用包装器。)
[1]使用新的auto
声明,其原因变得更加清晰。
答案 1 :(得分:0)
以下是libsass解析器的示例:
const char* interpolant(const char* src) {
return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src);
}
// Match a single character literal.
// Regex equivalent: /(?:x)/
template <char chr>
const char* exactly(const char* src) {
return *src == chr ? src + 1 : 0;
}
可以将规则传递给lex方法。