用名字标记 std::function?
Tagging std::function with a name?
我正在开发一个解析器组合器库,我真的希望我的解析器只是一些可调用对象:
typedef std::function<parse_result(parse_stream)> parser;
这使得解析器组合器很好,例如:
parser operator &(parser a, parser b) { return both(a,b); }
但是我想要两个功能:
1) 我希望将字符串文字自动提升为解析器,以便您可以执行以下操作:
parser option = "<" & regexp("[^+>]+");
2) 我希望解析器有一个名称,我可以将其用于错误格式设置。对于上面的 "both" 解析器,我可以打印出我期望的 a.name() 和 b.name() 例如。
到目前为止我尝试过的两个选项是
一个可调用的解析器class,这让我可以从字符串和std::function实例构建但是一个通用的可调用必须是首先转换为 std::function 然后从那里转换为解析器,C++ 不会进行两次隐式转换
从 std::function 继承,所以我可以隐式转换函数,但就仅将可调用对象转换为解析器而言,这似乎有很多陷阱。
有人对如何构建这个有任何想法吗?
您不需要标准函数的原始类型定义;你的解析器不仅仅是一个标准函数。
struct parser: std::function<parse_result(parse_stream)>{
using base = std::function<parse_result(parse_stream)>;
using base::base;
};
这应该允许
parser p = []( parse_stream str ) { return parse_result(7); };
因为我们使用继承构造函数来公开 parser
中的原始 std::function
构造函数。
虽然您可以覆盖:
parser operator&(parser a, parser b) { return both(a,b); }
通过将 &
放在 parse_result
或 parse_stream
的命名空间中来使用 typedef 版本,我建议不要这样做; standarizatoin 中已经讨论过限制这种模板参数 ADL。使用裸 parser
类型,放置此类运算符重载的位置很清楚。
此外,某些类型无法在 class 之外重载,例如 &=
。使用 struct
你可以在那里完成。
None 个修复
parser option = "<" & regexp("[^+>]+");
因为这里的问题是右侧不知道左侧在做什么(除非 regexp
是返回解析器的函数)。
首先这样做:
struct parser: std::function<parse_result(parse_stream)>{
using base = std::function<parse_result(parse_stream)>;
parser( char const* str ):
base( [str=std::string(str)](parse_stream stream)->parse_result { /* do work */ } )
{}
parser( char c ):
base( [c](parse_stream str)->parse_result { /* do work */ } )
{}
using base::base;
};
然后你可以添加
namespace parsing {
// parser definition goes here
inline namespace literals {
inline parser operator""_p( char const* str ) { return str; }
}
}
和 using namespace parsing::literals
表示 "hello"_p
是一个试图解析字符串 "hello"
.
的解析器
我正在开发一个解析器组合器库,我真的希望我的解析器只是一些可调用对象:
typedef std::function<parse_result(parse_stream)> parser;
这使得解析器组合器很好,例如:
parser operator &(parser a, parser b) { return both(a,b); }
但是我想要两个功能:
1) 我希望将字符串文字自动提升为解析器,以便您可以执行以下操作:
parser option = "<" & regexp("[^+>]+");
2) 我希望解析器有一个名称,我可以将其用于错误格式设置。对于上面的 "both" 解析器,我可以打印出我期望的 a.name() 和 b.name() 例如。
到目前为止我尝试过的两个选项是
一个可调用的解析器class,这让我可以从字符串和std::function实例构建但是一个通用的可调用必须是首先转换为 std::function 然后从那里转换为解析器,C++ 不会进行两次隐式转换
从 std::function 继承,所以我可以隐式转换函数,但就仅将可调用对象转换为解析器而言,这似乎有很多陷阱。
有人对如何构建这个有任何想法吗?
您不需要标准函数的原始类型定义;你的解析器不仅仅是一个标准函数。
struct parser: std::function<parse_result(parse_stream)>{
using base = std::function<parse_result(parse_stream)>;
using base::base;
};
这应该允许
parser p = []( parse_stream str ) { return parse_result(7); };
因为我们使用继承构造函数来公开 parser
中的原始 std::function
构造函数。
虽然您可以覆盖:
parser operator&(parser a, parser b) { return both(a,b); }
通过将 &
放在 parse_result
或 parse_stream
的命名空间中来使用 typedef 版本,我建议不要这样做; standarizatoin 中已经讨论过限制这种模板参数 ADL。使用裸 parser
类型,放置此类运算符重载的位置很清楚。
此外,某些类型无法在 class 之外重载,例如 &=
。使用 struct
你可以在那里完成。
None 个修复
parser option = "<" & regexp("[^+>]+");
因为这里的问题是右侧不知道左侧在做什么(除非 regexp
是返回解析器的函数)。
首先这样做:
struct parser: std::function<parse_result(parse_stream)>{
using base = std::function<parse_result(parse_stream)>;
parser( char const* str ):
base( [str=std::string(str)](parse_stream stream)->parse_result { /* do work */ } )
{}
parser( char c ):
base( [c](parse_stream str)->parse_result { /* do work */ } )
{}
using base::base;
};
然后你可以添加
namespace parsing {
// parser definition goes here
inline namespace literals {
inline parser operator""_p( char const* str ) { return str; }
}
}
和 using namespace parsing::literals
表示 "hello"_p
是一个试图解析字符串 "hello"
.