0

我正在尝试提出一个用于解析字符串(具有给定格式)的通用解决方案。例如,我希望能够解析包含数值列表(整数或浮点数)的字符串并返回 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函数的返回类型推断模板值。我不确定如何解决这个问题(或者甚至不确定是否可以解决它,因为设计方法可能完全有缺陷)。有谁知道解决我想要做的事情的方法?如果您能指出一种可能的方法来解决我在当前实施中遇到的问题,我将不胜感激。顺便说一句,我也绝对愿意接受完全不同的想法来解决这个问题。

4

2 回答 2

1

您不能基于返回值 [1] 重载函数。这正是标准 IO 库使用该结构的原因:

std::cin >> a >> b;

这可能不是你的小菜一碟——很多人不喜欢它,而且它确实不是没有问题——但它在为解析器提供目标类型方面做得很好。与静态parse<X>(const std::string&)原型相比,它还具有允许链接和流式传输的优势,如上所述。有时这不是必需的,但在许多解析上下文中它是必不可少的,并且使用operator>>实际上是一种非常酷的语法。[2]

标准库并没有做最酷的事情,那就是跳过字符串常量scanf样式并允许交错阅读。

vector<int> integers;
std::cin >> "[" >> interleave(integers, ",") >> "]";

但是,这可以定义。(可能最好在字符串文字周围使用显式包装器,但实际上我更喜欢这样;但如果你传递一个变量,你会想使用一个包装器)。


[1] 有了新的auto声明,其原因变得更加清晰。

[2] 另一方面,IO 操纵器是一个残酷的笑话。错误处理是可悲的。但你不可能拥有一切。

于 2012-12-12T00:20:51.583 回答
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 方法中。

于 2017-08-08T00:08:16.407 回答