C++ 在Boost Phoenix中获取局部变量的类型

C++ 在Boost Phoenix中获取局部变量的类型,c++,boost,metaprogramming,boost-phoenix,boost-proto,C++,Boost,Metaprogramming,Boost Phoenix,Boost Proto,我如何获得在一个有范围的Boost-Phoenix语句中使用的局部变量的类型?使用Phoenix和Proto,我可以提取Phoenix表达式的许多方面。例如,下面的代码公开了arity(3);标记类型(lambda_actor);和Phoenix lambda表达式的child-2标记类型(左移位): #include <boost/proto/proto.hpp> #include <boost/phoenix.hpp> namespace proto = boo

我如何获得在一个有范围的Boost-Phoenix语句中使用的局部变量的类型?使用Phoenix和Proto,我可以提取Phoenix表达式的许多方面。例如,下面的代码公开了arity(3);标记类型(lambda_actor);和Phoenix lambda表达式的child-2标记类型(左移位):

#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;
}
#包括
#包括
名称空间proto=boost::proto;
名称空间phoenix=boost::phoenix;
使用名称空间phoenix::local_名称;
结构Foo{const char str[6]=“Ok.\n”;};
int main(int argc,char*argv[])
{
自动f=phoenix::lambda(_a=17,_b=Foo())[

std::cout我假设您感兴趣的类型是
int
Foo
,如果这不是您想要的,请忽略这个答案。查看文档我无法找到获取这些类型的简单方法。但是如果您查看
f
中存储的原型表达式的类型,您可以看到
int
Foo
可以在第一个子代中的角色向量中找到。最终获得感兴趣类型所需的步骤可以在输出中看到,接下来您可以轻松创建一个实现所需功能的元函数。在这个简单的例子中,
get\u local\u type
使用索引访问有问题的类型。如果要通过名称访问它(使用
\u a
)您应该能够使用lambda表达式第二个子级的
map_local_index_to_tuple
中的数据获取与名称相关联的索引。使用
phoenix::detail::get_index
实现
get_local_type_from_name
定义的
它的第一个参数和您想要从中获取信息的占位符类型(更具体地说,它需要
phoenix::detail::local
,您可以使用占位符类型的
proto::result\u 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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间proto=boost::proto;
名称空间phoenix=boost::phoenix;
使用名称空间phoenix::local_名称;
名称空间融合=boost::fusion;
结构Foo{const char str[6]=“Ok.\n”;};
std::string demangle(const char*mangledName){
智力状态;
char*result=abi::_cxa_demangle(mangledName、nullptr、nullptr和status);
开关(状态){
案例1:

std::cerr+100非常感谢,这正是我想要的。可以说,使用
abi::\uuuucxa\u demangle
显示您的工作也是total类;现在我可以自己钓鱼了;)很高兴它有所帮助。我添加了一种从占位符的名称而不仅仅是其索引获取类型的方法,并将lambda表达式稍微更改为使用两种元函数。尽管我喜欢这个答案,但它有点蹩脚/拙劣(对不起,我不知道如何用英语表达)。我希望这不会阻止其他人给出更好的答案。如果有人这样做,您应该接受该答案。请注意,请求显然是专有的。您可能会发现只打印typeid().name()更方便并通过c++过滤器将程序的输出管道化。这通常更加方便,并且支持更多的编译器。