Getting local variable types in Boost Phoenix

How can I get the types of local variables used in a Boost Phoenix application? Using Phoenix and Proto, I can extract numerous aspects of Phoenix expression. For example, the following code exposes arity (3); tag type (lambda_actor); and the tag type child-2 (shift_left) of the Phoenix lambda expression:

#include <boost/proto/proto.hpp> #include <boost/phoenix.hpp> namespace proto = boost::proto; namespace phoenix = boost::phoenix; using namespace phoenix::local_names; struct Foo { const char str[6] = " Ok.\n"; }; int main(int argc, char *argv[]) { auto f = phoenix::lambda(_a = 17, _b = Foo()) [ std::cout << _a << phoenix::bind(&Foo::str,_b) ]; typedef typename proto::tag_of<decltype( f )>::type tag; typedef typename proto::tag_of<decltype(proto::child_c<2>(f))>::type tagc; static_assert(proto::arity_of<decltype(f)>::value==3,""); static_assert(std::is_same<tag, phoenix::tag::lambda_actor>::value,""); static_assert(std::is_same<tagc, proto::tag::shift_left>::value,""); return 0; } 

How can I get the types of local variables; in this example: _a and _b ?

+4
source share
1 answer

I assume that the types that interest you are int and Foo , if that is not what you need, please ignore this answer. Looking through the documentation, I could not find an easy way to get these types. But if you look at the type of proto expression stored in f , you will see that int and Foo can be found in the actors vector inside the first child. The steps you need to take to finally switch to interesting types can be seen in the output and after that you can easily create a metafound that does what you want. In this simple case, get_local_type uses an index to access the type in question. If you want to access it through the name (using _a ), you can get the index associated with the name using the data in map_local_index_to_tuple in the second child element of the lambda expression. Using phoenix::detail::get_index , which is defined here, the implementation of get_local_type_from_name also quite simple. In this metaphone, the above map is expected to be its first argument and the type of placeholder with which you want to receive information (more precisely, it needs phoenix::detail::local<phoenix::local_names::_a_key> , and you can get this using proto::result_of::value in the placeholder type) as its second.

 #include <iostream> #include <typeinfo> #include <string> #include <cxxabi.h> #include <type_traits> #include <boost/proto/proto.hpp> #include <boost/phoenix.hpp> namespace proto = boost::proto; namespace phoenix = boost::phoenix; using namespace phoenix::local_names; namespace fusion = boost::fusion; struct Foo { const char str[6] = " Ok.\n"; }; std::string demangle(const char* mangledName) { int status; char* result = abi::__cxa_demangle(mangledName, nullptr, nullptr, &status); switch(status) { case -1: std::cerr << "Out of memory!" << std::endl; exit(1); case -2: return mangledName; case -3: // Should never happen, but just in case? return mangledName; } std::string name = result; free(result); return name; } template <typename Lambda, int N> struct get_local_type { typedef typename proto::result_of::value<typename proto::result_of::child_c<Lambda,0>::type >::type vector_of_locals_type; typedef typename proto::result_of::value<typename fusion::result_of::at_c<vector_of_locals_type,N>::type >::type ref_type; typedef typename std::remove_reference<ref_type>::type type; }; template <typename Lambda, typename Arg> struct get_local_type_from_name { typedef typename proto::result_of::value<Arg>::type local_name; typedef typename proto::result_of::value<typename proto::result_of::child_c<Lambda,1>::type >::type map_type; typedef typename phoenix::detail::get_index<map_type,local_name>::type index; typedef typename get_local_type<Lambda,index::value>::type type; }; int main(int argc, char *argv[]) { auto f = phoenix::lambda(_b = 17, _a = Foo()) [ std::cout << _b << phoenix::bind(&Foo::str,_a) ]; std::cout << std::endl << "This is the whole lambda expression:" << std::endl; std::cout << std::endl << demangle(typeid(f).name()) << std::endl; std::cout << std::endl << "Take the first child:" << std::endl; std::cout << std::endl << demangle(typeid(proto::child_c<0>(f)).name()) << std::endl; std::cout << std::endl << "Then its value (this is a vector that contains the types you want):" << std::endl; std::cout << std::endl << demangle(typeid(proto::value(proto::child_c<0>(f))).name()) << std::endl; std::cout << std::endl << "Take the first element of that vector:" << std::endl; std::cout << std::endl << demangle(typeid(fusion::at_c<0>(proto::value(proto::child_c<0>(f)))).name()) << std::endl; std::cout << std::endl << "Take the value of that element:" << std::endl; std::cout << std::endl << demangle(typeid(proto::value(fusion::at_c<0>(proto::value(proto::child_c<0>(f))))).name()) << std::endl; typedef typename proto::tag_of<decltype( f )>::type tag; typedef typename proto::tag_of<decltype(proto::child_c<2>(f))>::type tagc; static_assert(proto::arity_of<decltype(f)>::value==3,""); static_assert(std::is_same<tag, phoenix::tag::lambda_actor>::value,""); static_assert(std::is_same<tagc, proto::tag::shift_left>::value,""); typedef typename get_local_type<decltype(f),0>::type type_of_1st; typedef typename get_local_type<decltype(f),1>::type type_of_2nd; typedef typename get_local_type_from_name<decltype(f),_a_type>::type type_of_a; typedef typename get_local_type_from_name<decltype(f),decltype(_b)>::type type_of_b; static_assert(std::is_same<type_of_1st,int>::value,""); static_assert(std::is_same<type_of_2nd,Foo>::value,""); static_assert(std::is_same<type_of_a,Foo>::value,""); static_assert(std::is_same<type_of_b,int>::value,""); return 0; } 
+1
source

Source: https://habr.com/ru/post/1482467/


All Articles