如何找出lambda的自动类型参数中的哪些方法?
How to find out what methods in auto-type arguments of lambda?
我已经与 Boost.Spirit 搏斗了一个星期。请原谅我对 C++ 的模板元编程的无知,但我忍不住要问:如果你不知道一个该死的变量类型,你怎么知道你能用它做什么?例如:
namespace qi = boost::spirit::qi;
qi::on_error<qi::fail>(rule,
[](auto& args, auto& context, auto& r) {
// what to do with args, context and r?
}
);
它不像 Python,您可以在其中使用 dir()
或 help()
来获取有关某些变量的信息。我知道我可以使用 typeid(..).name()
来找出变量的类型,但通常结果是一些长的不可读的文本,例如:
struct boost::fusion::vector<class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > & __ptr64,class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > const & __ptr64,class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > const & __ptr64,struct boost::spirit::info const & __ptr64>
所以只剩下一种方法了:参考文档。但问题是:Spirit 的文档不完整。在这个例子中,它只对 "Error Handling Tutorial":
中的这些参数说了几句话
on_error declares our error handler:
on_error<Action>(rule, handler)
...
handler is the actual error handling function. It expects 4 arguments:
Arg
Description
first
The position of the iterator when the rule with the handler was entered.
last
The end of input.
error-pos
The actual position of the iterator where the error occurred.
what
What failed: a string describing the failure.
但是如你所见,on_error
的第二个参数不是一个4参数函数,而是一个3参数函数(args、context和r)。文档有错吗?我在哪里可以找到这些参数的方法? Spirit 有每个函数的 API 文档吗?
最简单的方法:
qi::on_error<qi::fail>(rule,
[](auto& args, auto& context, auto& r) {
std::cerr << __PRETTY_FUNCTION__ << std::endl;
}
);
例如GCC 这会打印完整的签名,包括推导的类型参数。
文档有误吗?
请注意,它确实需要 4 个参数:
using namespace qi::labels;
qi::on_error<qi::error_handler_result::fail>(rule, f_(_1, _2, _3, _4));
当您安装像 f_
这样的处理程序时:
struct F {
using result_type = void;
template <typename... Args>
void operator()(Args&&...) const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
boost::phoenix::function<F> f_{};
它打印 (Live):
"expected" -> true
void Parser::F::operator()(Args&& ...) const [with Args = {const char*&, const char* const&, const char* const&, const boost::spirit::info&}]
"unexpected" -> false
如您所见,文档没有错误或不完整。你的期望是,因为你没有得到 handler
代表一个 延迟函数 又名。 Phoenix Actor。我猜文档所做的“不正当”事情是假设您从实际示例中看到,它紧接在您引用的文档之前:
on_error<fail>
(
xml
, std::cout
<< val("Error! Expecting ")
<< _4 // what failed?
<< val(" here: \"")
<< construct<std::string>(_3, _2) // iterators to error-pos, end
<< val("\"")
<< std::endl
);
在这里,表达式 std::cout << val("Error! Expecting ") << _4 << val(" here: \"") << construct<std::string>(_3, _2) << val("\"") << std::endl
似乎很明显 而不是 字面上的“一个有 4 个参数的函数”。不过,它是一个 Phoenix 表达式,定义了一个接受 4 个参数的 actor。
您做过发现演员实际上仍然是根据可调用对象实现的。它“接受”了 3 个参数,分别是 Phoenix actors 和 Spirit 上下文参数的技术实现细节。
问题是抽象层次的脱节。文档记录了库接口,你不小心看到了实现细节。
TL;DR
lambda 不是延迟的 Phoenix actor。
详细了解延迟演员的工作原理,例如具有语义动作:
关于 [SO] 的一些答案突出了 Actor 签名、上下文和实现签名之间的关系:
How to avoid boost::phoenix when generating with boost::spirit::karma
boost spirit semantic action parameters
它会产生一个编译时错误,但是如果你有一个 class 模板声明,比如
template <typename T> struct get_type;
然后尝试使用提供的类型创建 get_type
对象将产生错误,并且在错误消息中它会告诉您提供给 get_type
的类型是什么。例如使用
int main()
{
auto lambda = [](auto first, auto second, auto third)
{
get_type<decltype(first)>{};
get_type<decltype(second)>{};
get_type<decltype(third)>{};
};
lambda(A{}, B{}, int{});
}
产生类似
的错误信息
main.cpp:20:9: error: invalid use of incomplete type 'struct get_type<A>'
20 | get_type<decltype(first)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<A>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
main.cpp:21:9: error: invalid use of incomplete type 'struct get_type<B>'
21 | get_type<decltype(second)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<B>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
main.cpp:22:9: error: invalid use of incomplete type 'struct get_type<int>'
22 | get_type<decltype(third)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<int>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
告诉 use first
是 A
,第二个是 B
,third
是 int
,如 live example.
我已经与 Boost.Spirit 搏斗了一个星期。请原谅我对 C++ 的模板元编程的无知,但我忍不住要问:如果你不知道一个该死的变量类型,你怎么知道你能用它做什么?例如:
namespace qi = boost::spirit::qi;
qi::on_error<qi::fail>(rule,
[](auto& args, auto& context, auto& r) {
// what to do with args, context and r?
}
);
它不像 Python,您可以在其中使用 dir()
或 help()
来获取有关某些变量的信息。我知道我可以使用 typeid(..).name()
来找出变量的类型,但通常结果是一些长的不可读的文本,例如:
struct boost::fusion::vector<class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > & __ptr64,class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > const & __ptr64,class boost::spirit::lex::lexertl::iterator<class boost::spirit::lex::lexertl::functor<struct boost::spirit::lex::lexertl::token<class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::vector<__int64,struct String,struct Symbol,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na,struct boost::mpl::na>,struct boost::mpl::bool_<1>,unsigned __int64>,class boost::spirit::lex::lexertl::detail::data,class std::_String_iterator<class std::_String_val<struct std::_Simple_types<char> > >,struct boost::mpl::bool_<1>,struct boost::mpl::bool_<1> > > const & __ptr64,struct boost::spirit::info const & __ptr64>
所以只剩下一种方法了:参考文档。但问题是:Spirit 的文档不完整。在这个例子中,它只对 "Error Handling Tutorial":
中的这些参数说了几句话on_error declares our error handler:
on_error<Action>(rule, handler)
...
handler is the actual error handling function. It expects 4 arguments:
Arg Description first The position of the iterator when the rule with the handler was entered. last The end of input. error-pos The actual position of the iterator where the error occurred. what What failed: a string describing the failure.
但是如你所见,on_error
的第二个参数不是一个4参数函数,而是一个3参数函数(args、context和r)。文档有错吗?我在哪里可以找到这些参数的方法? Spirit 有每个函数的 API 文档吗?
最简单的方法:
qi::on_error<qi::fail>(rule,
[](auto& args, auto& context, auto& r) {
std::cerr << __PRETTY_FUNCTION__ << std::endl;
}
);
例如GCC 这会打印完整的签名,包括推导的类型参数。
文档有误吗?
请注意,它确实需要 4 个参数:
using namespace qi::labels;
qi::on_error<qi::error_handler_result::fail>(rule, f_(_1, _2, _3, _4));
当您安装像 f_
这样的处理程序时:
struct F {
using result_type = void;
template <typename... Args>
void operator()(Args&&...) const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
boost::phoenix::function<F> f_{};
它打印 (Live):
"expected" -> true
void Parser::F::operator()(Args&& ...) const [with Args = {const char*&, const char* const&, const char* const&, const boost::spirit::info&}]
"unexpected" -> false
如您所见,文档没有错误或不完整。你的期望是,因为你没有得到 handler
代表一个 延迟函数 又名。 Phoenix Actor。我猜文档所做的“不正当”事情是假设您从实际示例中看到,它紧接在您引用的文档之前:
on_error<fail> ( xml , std::cout << val("Error! Expecting ") << _4 // what failed? << val(" here: \"") << construct<std::string>(_3, _2) // iterators to error-pos, end << val("\"") << std::endl );
在这里,表达式 std::cout << val("Error! Expecting ") << _4 << val(" here: \"") << construct<std::string>(_3, _2) << val("\"") << std::endl
似乎很明显 而不是 字面上的“一个有 4 个参数的函数”。不过,它是一个 Phoenix 表达式,定义了一个接受 4 个参数的 actor。
您做过发现演员实际上仍然是根据可调用对象实现的。它“接受”了 3 个参数,分别是 Phoenix actors 和 Spirit 上下文参数的技术实现细节。
问题是抽象层次的脱节。文档记录了库接口,你不小心看到了实现细节。
TL;DR
lambda 不是延迟的 Phoenix actor。
详细了解延迟演员的工作原理,例如具有语义动作:
关于 [SO] 的一些答案突出了 Actor 签名、上下文和实现签名之间的关系:
How to avoid boost::phoenix when generating with boost::spirit::karma
boost spirit semantic action parameters
它会产生一个编译时错误,但是如果你有一个 class 模板声明,比如
template <typename T> struct get_type;
然后尝试使用提供的类型创建 get_type
对象将产生错误,并且在错误消息中它会告诉您提供给 get_type
的类型是什么。例如使用
int main()
{
auto lambda = [](auto first, auto second, auto third)
{
get_type<decltype(first)>{};
get_type<decltype(second)>{};
get_type<decltype(third)>{};
};
lambda(A{}, B{}, int{});
}
产生类似
的错误信息main.cpp:20:9: error: invalid use of incomplete type 'struct get_type<A>'
20 | get_type<decltype(first)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<A>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
main.cpp:21:9: error: invalid use of incomplete type 'struct get_type<B>'
21 | get_type<decltype(second)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<B>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
main.cpp:22:9: error: invalid use of incomplete type 'struct get_type<int>'
22 | get_type<decltype(third)>{};
| ^~~~~~~~
main.cpp:14:30: note: declaration of 'struct get_type<int>'
14 | template <typename T> struct get_type;
| ^~~~~~~~
告诉 use first
是 A
,第二个是 B
,third
是 int
,如 live example.