Search code examples
c++classtemplatescode-generationauto-generate

An in code class auto generator from a string of text or some other mechanism


I would like to be able to automatically generate a class in code if possible.

I know that I can have a text or script file that can be opened and the contents of that file be loaded into either a vector of strings or a string stream, and from there write back to a file or set of files to generate a class. I'm not interested in the details of the parsing aspect and this is not what I'm actually after.

Let's say I have a text file that looks something like this: My current pseudo file above is much longer with more verbose detailed explanations; but omitted here for simplicity. If you feel that it is needed don't hesitate to ask and I will post it.

script

// The finalized scripting file & its parser will not have any comments within code sections.
// Comments can be found before & after the <begin:file> & <end:file> sections

// This is the beginning of the file and whether or not a header and or cpp file
// is generated or not. If not then the idea is to generate the class in code directly.
// <begin:file "Foo.h"> // header only otherwise 
// <being:file "Foo.h", "Foo.cpp"> for both header and cpp 

<begin:file> 
<class:"Foo">
<private:>
  <variables: int=mX,mY,mZ float=mWidth,mHeight>
<public:>
  <constructor:defualt=t, init=t>
  <constructor:copy=t> // automatically generates both copy() & operator=() as = default;
  <constructor:copy=f> // declares both copy() & operator() as = delete;
  <destructor:default=t>
<end:class>
<end:file>

In the above script where I have <begin:file> since there are no strings after it; this means I do not want to write to files to create a header and or cpp file. Since they are omitted I would like to generate this class in code.

I do not want to resort to using macros. I could use templates if possible or some other mechanism.

What I am not sure about is this: let's say I'm at the part where I read in <class:"Foo"> this will tell my parser that I want a class named Foo and this would be it's shell:

class Foo {}; 

As expected, however we can not write the ending }; part yet because we have not reached the <end:class> part. So at this point we need to write out class Foo { and the part or problem that I'm seeing here is I do not know how I would be able to take the text or string such as std::string name("Foo"); and appended that after the c++ key word class. Pseudo example:

{
     std::string name("Foo");

     class name {
     public:
         int x; 
     };

     std::cout << name << std::endl; // compiles and prints to the console "Foo"
     std::cout << name.y << std::end; // will not compile.
}

The problem here is that after c++'s key word class it is expecting an identifier and the compiler will not accept this. The compiler will declare a string named name that has the contents of "Foo", then below when trying to declare the class using that string, it doesn't see the string and names to the class with the identifier name. Then if you try to use the class afterwards it doesn't find the class at all but rather it finds the string called name. Is it possible to use some kind of already built in feature to append the needed text here to automatically generate a class within code without having to type it out? I am not sure of how to extract the text from a string to use that as the identifier of the class's name.


Conclusion

From reading the comments and answer provided in my related question; it then proves my initial assumptions that I didn't mention to be true. It can not be done. This does resort into having to write the class to their respective files from the parsers point of view.


Solution

  • Sorry, but this just isn't how C++ works. A compiler understands things like the keyword class and the names of members, and typically puts all that understanding to use to convert all that into machine code, which normally uses just lots of raw pointers and offsets, not the names of members or things like that. Only after the compiler is finished, you run your program, and a typical program does not itself contain much of any capability at all to understand things like classes, member names, or assignment operators.

    So what options do you have? You could write some utilities that are capable of doing some of the things a general class would do, but you won't be able to refer to it in the same ways as a class the compiler learned about from a header file within your program. This might look something like:

    {
        CustomClass myclass( "Foo.cls" );
        CustomObject obj = myclass.create(); // default constructor
        CustomObject obj_copy = obj; // copy constructor
    }
    

    Or you might do something that compiles and loads plugins at runtime, though there are a few complications to attempting that. This still doesn't let you use the custom class like one compiled into your program, but it allows arbitrary C++ code (which is both powerful and dangerous, since someone could accidentally or maliciously break just about anything that way). This would involve converting your configuration file to an actual temporary C++ source file you write out, running the compiler with special options to create a "shared library" (Unix, including Linux) or "DLL" (Windows), then loading that library using dlopen (many Unix flavors including Linux) or LoadLibrary (Windows). And for the compile step, this means any computer where you run your program needs the compiler installed, and it should probably be a reasonably close version to the compiler version you used to compile your program. If this compiler is on a special path, how will your program be told that path?

    Plus you would need to design a plugin architecture, considering things like:

    • How does the plugin interface with the program? Does it provide a function that just inputs and outputs vectors of strings? Does it provide a function to create a class object derived from some abstract base class?

    • If the plugin needs to use any base classes or specialized functions specific to your program, how will you make sure the needed header files are provided to the compiler when compiling the plugin?