Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Code Generation

In my epic quest of making C++ do things it shouldn't, I am trying to put together a compile time generated class.

Based on a preprocessor definition, such as (rough concept)

CLASS_BEGIN(Name)  
    RECORD(xyz)  
    RECORD(abc)

    RECORD_GROUP(GroupName)  
        RECORD_GROUP_RECORD(foo)  
        RECORD_GROUP_RECORD(bar)  
    END_RECORDGROUP   
END_CLASS

While I am fairly sure I generate a class that reads the data from the file system using this sort of structure (Maybe even doing it using Template Metaprogramming), I don't see how I can generate both the functions to access the data and the function to read the data.

I would want to end up with a class something like this

class Name{
    public:
    xyz_type getxyz();
    void setxyz(xyz_type v);

    //etc

    list<group_type> getGroupName();

    //etc

    void readData(filesystem){
         //read xyz
         //read abc
         //etc
    }
};

Does anyone have any idea if this is even possible?

--EDIT--

To clarify the intended usage for this. I have files in a standard format I want to read. The format is defined already, so it is not open to change. Each file can contain any number records, each of which can contain any number sub records.

The numerous record types each contain a diffrent set of sub records, but they can be are defined. So for example the Heightmap record must contain a Heightmap, but can optional contain normals.

So I would want to define a Record for that like so:

CLASS_BEGIN(Heightmap)  
    RECORD(VHDT, Heightmap, std::string) //Subrecord Name, Readable Name, Type  
    RECORD_OPTIONAL(VNML, Normals, std::string)  
END_CLASS  

For which I would want to output something with the functionality of a class like this:

class Heightmap{
    public:
    std::string getHeightmap(){
        return mHeightmap->get<std::string>();
    }
    void setHeightmap(std::string v){
        mHeight->set<std::string>(v);
    }

    bool hasNormal(){
        return mNormal != 0;
    }
    //getter and setter functions for normals go here

    private:
    void read(Record* r){
        mHeightmap = r->getFirst(VHDT);
        mNormal = r->getFirst(VNML);
    }


    SubRecord* mHeightmap, mNormal;
}

The issue I am having is that I need every preprocessor definition twice. Once for defining the function definition within the class, and once for creating the read function. As the preprocessor is purely functional, I cannot push the data to a queue and generate the class on the END_CLASS marco definition.

I cannot see a way around this issue, but wondered if anyone who has a greater understanding of C++ did.

like image 477
Yacoby Avatar asked Jun 05 '09 16:06

Yacoby


1 Answers

If you are looking for a way to serialize/deserialize data with C++ code generation, I would look at Google protobufs (http://code.google.com/p/protobuf/) or Facebook's Thrift (http://incubator.apache.org/thrift/).

For protobufs, you write a data definition like so:

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

A Person C++ class is then generated that lets you load, save and access this data. You can also generate python, java, etc.

like image 134
Joe Beda Avatar answered Oct 11 '22 19:10

Joe Beda