Как я могу получить типы локальных переменных, используемых в заявлении Boost Phoenix? Используя Phoenix и Proto, я могу извлечь множество аспектов выражения Phoenix. Например, следующий код предоставляет arity (3); тип тега (lambda_actor); и тип тега child-2 (shift_left) лямбда-выражения Phoenix:
#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;
}
Как я могу получить типы локальных переменных; в этом примере: _a
а также _b
?
Я предполагаю, что интересующие вас типы int
а также Foo
, если это не то, что вы после, пожалуйста, игнорируйте этот ответ. Просматривая документацию, я не смог найти простой способ получить эти типы. Но если вы посмотрите на тип выражения прото, хранящегося в f
ты это видишь int
а также Foo
можно найти в векторе актеров внутри первого ребенка. Шаги, которые вам нужно сделать, чтобы, наконец, добраться до интересных типов, можно увидеть в выводе, и после этого вы можете легко создать метафункцию, которая делает то, что вы хотите. В этом простом случае get_local_type
использует индекс для доступа к рассматриваемому типу. Если вы хотите получить к нему доступ по имени (используя _a
) вы должны иметь возможность получить индекс, связанный с именем, используя данные в map_local_index_to_tuple
во втором потомке лямбда-выражения. С помощью phoenix::detail::get_index
это определено Вот реализации get_local_type_from_name
тоже довольно просто. Эта мета-функция ожидает указанную выше карту в качестве первого аргумента и тип заполнителя, из которого вы хотите получить информацию (точнее, ей нужно phoenix::detail::local<phoenix::local_names::_a_key>
и вы можете получить это с помощью proto::result_of::value
на тип заполнителя) в качестве второго.
#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;
}
Других решений пока нет …