【问题标题】:Obtaining the types of local variables in Boost Phoenix获取Boost Phoenix中局部变量的类型
【发布时间】:2013-05-23 21:44:19
【问题描述】:

如何获取作用域 Boost Phoenix 语句中使用的局部变量的类型?使用 Phoenix 和 Proto,我可以提取 Phoenix 表达式的多个方面。例如,以下代码公开了arity (3);标签类型(lambda_actor); Phoenix lambda 表达式的 child-2 标记类型 (shift_left):

#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?

【问题讨论】:

    标签: c++ boost metaprogramming boost-phoenix boost-proto


    【解决方案1】:

    我假设您感兴趣的类型是intFoo,如果这不是您所追求的,请忽略此答案。查看文档,我无法找到获取这些类型的简单方法。但是,如果您查看存储在 f 中的 proto 表达式的类型,您会发现 intFoo 可以在第一个孩子内的演员向量中找到。您可以在输出中看到最终获得有趣类型所需的步骤,然后您可以轻松创建一个执行您想要的元函数。在这个简单的例子中,get_local_type 使用索引来访问有问题的类型。如果您想通过名称访问它(使用_a),您应该能够使用lambda 表达式的第二个子项中map_local_index_to_tuple 中的数据获取与名称关联的索引。使用定义为herephoenix::detail::get_index 实现get_local_type_from_name 也很容易。这个元函数需要上面提到的地图作为它的第一个参数,以及你想要从中获取信息的占位符的类型(更具体地说,它需要phoenix::detail::local&lt;phoenix::local_names::_a_key&gt;,你可以在占位符的类型上使用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;
    }
    

    【讨论】:

    • +100 非常感谢,这正是我所追求的。可以说,使用abi::__cxa_demangle 来展示您的工作也是全班;现在我可以自己钓鱼了;)
    • 很高兴它有帮助。我添加了一种从占位符名称中获取类型的方法,而不仅仅是它的索引,并稍微更改了 lambda 表达式以使用这两个元函数。尽管我喜欢这个答案,但它有点蹩脚/粗制滥造(对不起,我不知道如何用英语表达)。我希望这不会阻止其他人给出更好的答案。如果有人这样做,你应该接受这个答案。
    • 请注意,拆解显然是专有的。您可能会发现只打印 typeid().name() 并通过 c++filt 管道输出程序的输出更方便。这通常更方便,并且支持更多的编译器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多