C++ 已知类集合中的反射

C++ 已知类集合中的反射,c++,templates,metaprogramming,C++,Templates,Metaprogramming,我试图遍历一个对象层次结构,而对象层次结构是由一组已知的类组成的,这些类通过组合组合而成。我想构建一个对象模型,以图形方式显示层次结构/组合。构图是根据一些规则完成的,但它是流动和灵活的 相当多的类(25+)可用,构建块的数量正在增加。如果我在其他类型中搜索每种类型,那么我们有大量可能的组合 我可以构建一个大表,在其中搜索给定类型的每个其他对象,并递归地构建对象模型,但可能有更好的方法,因此我在这里询问专家 是否可能知道在运行时特定类型上是否存在函数/成员变量 我的示例代码如下所示: #incl

我试图遍历一个对象层次结构,而对象层次结构是由一组已知的类组成的,这些类通过组合组合而成。我想构建一个对象模型,以图形方式显示层次结构/组合。构图是根据一些规则完成的,但它是流动和灵活的

相当多的类(25+)可用,构建块的数量正在增加。如果我在其他类型中搜索每种类型,那么我们有大量可能的组合

我可以构建一个大表,在其中搜索给定类型的每个其他对象,并递归地构建对象模型,但可能有更好的方法,因此我在这里询问专家

是否可能知道在运行时特定类型上是否存在函数/成员变量

我的示例代码如下所示:

#include <iostream>

struct Generic {};

struct SimpleType {int toString(){return 0;}};

enum ETypeVal{eVal1 = 0, eVal2 = 1, eVal3 = 2};


template <typename ETypeVal val>
struct Hello
{
    int toString(){return 0;}
};

template <> struct Hello<eVal2>
{
    int toString(){return 1;}
};

template <> struct Hello<eVal3>
{   
};


template <class Type>
class TypeHasToString
{
public:
    typedef bool Yes;
    typedef short No;

    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));

private:

    template <typename T, T> struct TypeCheck;

    template <typename T> struct ToString
    {
        typedef int (T::*fptr)();
    };

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
    template <typename T> static No  HasToString(...);
};

int main(int argc, char *argv[])
{
    // all this works fine
    std::cout << TypeHasToString<Generic>::value << std::endl;
    std::cout << TypeHasToString<SimpleType>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal1>>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal2>>::value << std::endl;
    std::cout << TypeHasToString<Hello<eVal3>>::value << std::endl;

    // Unable to deduce for type that are not known at compile time
    // Is it possible to remove this limitation ?
    for(int val = eVal1; val <= eVal3; val++)
    {
        std::cout << TypeHasToString< Hello< (ETypeVal)val > >::value << std::endl;
    }

    return 0;
}
#包括
结构泛型{};
结构SimpleType{int-toString(){return 0;}};
枚举ETypeVal{eVal1=0,eVal2=1,eVal3=2};
模板
结构你好
{
int-toString(){return 0;}
};
模板结构Hello
{
int-toString(){return 1;}
};
模板结构Hello
{   
};
模板
类类型hastoString
{
公众:
typedef bool是;
typedef短No;
静态布尔常量值=(sizeof(HasToString(0))==sizeof(Yes));
私人:
模板结构类型检查;
模板结构ToString
{
typedef int(T::*fptr)();
};
模板静态Yes HasToString(TypeCheck*);
模板静态无HasToString(…);
};
int main(int argc,char*argv[])
{
//所有这些都很好

STD::CUT

我认为在这种情况下需要运行时多态性。使用接口代替模板来解决此类问题。接口将给出关于对象中方法的知识,但不会对成员变量表示任何说明。因此在标准C++中没有可用的反射。(C++提供的唯一东西是Type信息操作程序,在某些情况下可能会帮助您),您可以尝试为编译器找到一些扩展,这些扩展将为您提供反射机会。

我认为在这种情况下您需要运行时多态性。对于此类问题,请使用接口而不是模板。接口将提供有关对象中方法的知识,但不会说明成员vaRiabess。所以在标准C++中没有反射可用(C++提供的唯一东西是Type信息操作程序,在某些情况下可能会帮助你)你可以尝试为编译器找到一些扩展,这样会给你带来反射机会。

< P>我们在C++中没有运行时反射。但是我们有不同的东西,大多数C++程序员喜欢比反射更好;----- 如果我理解你的问题,你需要构建某种对象浏览器,你知道你所有的对象类型。所谓“你知道你所有的对象类型”,我的意思是“你不会从一个没有编码的dll中得到一个指针另一端的对象”


这样,也许你可以使用.Load库是用来迭代聚合的,在这样做时,检索每个聚合成员的数据和类型。它就像是结构成员上的迭代器,如果我必须把它放在一个华丽的方式上。当然可以用你的自定义类型。

< P>我们在C++中没有运行时反射。但是我们有D。不同的东西,大多数C++程序员喜欢比反射好;-) 如果我理解你的问题,你需要构建某种对象浏览器,你知道你所有的对象类型。所谓“你知道你所有的对象类型”,我的意思是“你不会从一个没有编码的dll中得到一个指针另一端的对象”


那么,也许您可以使用?所说的库是为迭代聚合而设计的,在这样做的同时,检索每个聚合成员的数据和类型。如果我必须以华丽的方式将它放在结构成员上,它就像迭代器一样。当然,您可以使用自定义类型进行迭代。

如果在编译时不这样做,您在运行时无法知道。在编译时,你需要知道一个函数的代码。你可以用它制作一个宏,用于任何你想检查的函数。(宏免责声明:在这种情况下,宏是好的,这就是BOOST_MPL_XXX_TEMPLATE_DEF的工作原理)


或者,还有dsign提到的boost::fusion。但我更喜欢另一个:boost::reflect(实际上在boost中没有)。宏语法更简单(不需要在宏中提及类型),代码非常轻量级。然后还有完整的功能boost::mirror(),在boost中还没有,它更完整,甚至有一个代码生成器为您创建宏调用和java风格的运行时反射。

如果在编译时没有,您在运行时无法知道。对于一个函数,您在编译时就可以知道代码。您可以从中生成一个宏,用于任何要编译的函数见鬼。(宏免责声明:在这种情况下,宏是好的,这就是BOOST\u MPL\u XXX\u TEMPLATE\u DEF的工作原理)


或者,还有dsign提到的boost::fusion。但我更喜欢另一个:boost::reflect(实际上在boost中没有)。宏语法更简单(不需要在宏中提及类型),代码非常轻量级。然后还有完整的功能boost::mirror(),在boost中还没有,它更完整,甚至有一个代码生成器来为您创建宏调用和java风格的运行时反射。

我已经使用boost::mpl来进行迭代和打印值。大多数情况下,如果没有这些,应该是可能的,但我强烈建议使用它。此外,我还修复了您的co中的一些问题de.您可能还希望使用BOOST_HAS_XXX而不是您的自制解决方案(您的SFINAE风格相当笨拙)

#包括
#包括
#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/for_each.hpp>


struct Generic {};

struct SimpleType {int toString(){return 0;}};

enum ETypeVal{ eVal1 = 0, eVal2 = 1, eVal3 = 2};

template <ETypeVal val>
struct Hello
{
  int toString(){return 0;}
};

template <> struct Hello<eVal2>
{
  int toString(){return 1;}
};

template <> struct Hello<eVal3>
{   
};


template <class Type>
class TypeHasToString
{
public:
  typedef bool Yes;
  typedef short No;
private:

  template <typename T, T> struct TypeCheck;

  template <typename T> struct ToString
  {
    typedef int (T::*fptr)();
  };

  template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
  template <typename T> static No  HasToString(...);

public:
  static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));
};

template<typename val>
struct make_hello { typedef Hello< ETypeVal(val::value)> type; };

struct print_seq {
  template<typename T>
  void operator()(const T&) const {
    std::cout << T::value << std::endl;
  }
};

int main()
{
  using namespace boost::mpl;
  // maybe have a last enum here
  typedef range_c<int, eVal1, eVal3 + 1>::type range; 
  // range has no clear so we need the inserter
  typedef transform<range, make_hello<_1>, back_inserter< vector0<> > >::type hellos;
  typedef transform< hellos, TypeHasToString<_1> >::type booleans;
  // namespace for clarity
  boost::mpl::for_each<booleans>( print_seq() );

  return 0;
}