Sign in to follow this  

[C++] Scoping, embedded classes, inheritance, and template fun

This topic is 4016 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to think of a simple system to statically define types in the easiest way possible. I want to do it in such a way that if a user does not want to use this 'extended' feature, he/she/it can 'bypass' it using default template parameters. These are my thoughts on it, which seem as though they might compile (if I can figure how to template in the global type): [Assume scoping is adequate]
class Object {
 struct Type; //These aren't inherited, just simple data, name, parent, etc
 Type *__type; //The type this object is
  typename<Type &T_type=Type::null> //How to have it pass type? Ref, ptr, simple?
 class Templ : Object {
  inline Templ() { __type=&T_type; } //'Statically' set type - Type is included in def
 };
};
//Class inheriting this object
 extern Object::Type tBob;
class Bob : public Object::Templ<tBob> {
 //Constructor: Object(), Object::Templ<tBob>(), Bob()
};

Right now, in simple code, the user either has to manually set the type (which gets repetitous), Another, more organized / automatic option, a little more abstract on the template abuse: [Something I would like to do]:
class Object {
 ... //Same stuff as above
 static Type type;
  template<typename T=Object>
 class Templ {
  inline Templ() { __type=&T::type; } //It knows about the static type
 };
};
class Bob : Object::Templ<Bob> {
 static Type type; //So now it is easily refered to be 'Bob::type' instead of 'tBob'
  //Object::Templ<Bob> automatically knows of this (somehow, the compiler can scan ahead)
}

Obviously, this doesn't compile at all (with all the pre-definition refereneces). Is there any plausible, effective way to do this without massive workarounds? This isn't really out of necessity, but rather curiosity and hope for some general organization. The basic format I'm thinking of is like the first, more concrete one, and simple have a macro for it (if I have to pass a pointer for the template parameter). Sorry if I'm a little unclear in my code or explanations - just a little groggy. I'm probably going to come back to this and reorganize it if I have the time.

Share this post


Link to post
Share on other sites
I'm a little confused as to exactly what you're trying to accomplish, but I'll give it a shot. I also feel compelled to point out that a leading double underscore neither contributes meaningful information, nor is well advised - identifiers starting with a double underscore, or underscore followed by a capital letter, are reserved for the implementation in all scopes [1]. I've shifted to "_type", merely because type is already used and I'm having a hard time figuring out exactly what you're getting at with this system.

You seem to be attempting to shift from the first to the second, with a lot of vauge non-concrete examples, but I submit to you something similar to the second snippet that compiles:

class Object {
public:
struct Type {};

template< typename T = Object >
class Templ;

static Type type;
protected:
Type * _type;
};
Object::Type Object::type;

template< typename T >
class Object::Templ : public Object {
public:
inline Templ() { _type=&T::type; }
};

class Bob : public Object::Templ<Bob> {
using Object::Templ<Bob>::Type;
public: //Templ<Bob> has no access to Bob::type otherwise
static Type type;
};
Object::Type Bob::type;

int main () {
Bob bob;
}



I'm not sure why you're doing Object::Types by hand, though, and this is likely a superior solution:

class Object {
public:
struct Type {};

template< typename T = Object >
class Templ;
protected:
Type * _type;
};

template< typename T >
class Object::Templ : public Object {
public:
inline Templ() { _type=&type; }

protected: //or whatever
static Type type; //each Templ<T> is a seperate class, and will get a seperate version of this variable
};

template < typename T >
Object::Type Object::Templ<T>::type;

class Bob : public Object::Templ<Bob> {
public:
};

int main () {
Bob bob;
}




A final refactoring yields a slightly smaller object, and reaches the "local optimal" of my refactoring instinct (which switches to a postfix underscore only when it directly corresponds to an equivilantly named function otherwise):

class Object {
public:
struct Type {};

template< typename T = Object >
class Templ;

protected: //or whatever
virtual Type & type() const = 0; //constness desires may be different
};

template< typename T >
class Object::Templ : public Object {
static Type type_;
protected:
virtual Type & type() const { return type_; }
};

template < typename T >
Object::Type Object::Templ<T>::type_;

class Bob : public Object::Templ<Bob> {
public:
//all legwork done automatically, just use .type()
};

class Billy : public Object::Templ<Billy> {
public:
//all legwork done automatically, just use .type()
};

class Bush : public Object::Templ<Bush> {
public:
//all legwork done automatically, just use .type()
};

int main () {
Bob bob;
}


Share this post


Link to post
Share on other sites
MaulingMonkey >> Yes, that's essentially what I wanted. What helped me the most is reading that the statics were stored per-class with templating (don't know why I didn't think about that).
This is what I've gotten to so far: (I've given a lot more of the structure, but it's still relatively simple)
//Once again, assume all scoping/forwarding is correct
typedef (Object*)(*OBJ_FUNC)();
class Object {
class Type {
Type(string name,Type *parent=NULL,OBJ_FUNC func);
template<typename T>
static Object* NewFunc() { return new T; }
};
Type *__type; //The type this object is
//Standard typing
//Automatic type-handling (inherent type by template)
template<typename T=Object,const char *tname="",typename Parent=Object>
class Auto : public Parent {
static Type type;
inline Auto() { __type=&type; }
};
friend class Auto; //This doesn't have to be templating, right?
static Type type; //Static type - Name?
};
static Object::Type Object::type("null");
template<typename T=Object,const char *tname="",typename Parent=Object>
static Object::Type Object::Auto::type(tname,&Parent::type,&Object::Type::NewFunc<T>);





Of course, the new problem with not having this 'type system' manual is that it can be corrupted by changing the header (templating and all that jazz) and not recompiling the source - but of course, as long as someone handles everything correctly, this shouldn't be too much of a problem.

Also, I'm not able to compile it right now, since I have to fix a couple of other errors in the engine, but now it should be relatively simple to define a new object (without overusing macros).
Elaboration:
//Old Style of defining objects
extern Object::Type tBob;
class Bob : public Object {
...
};
//In source
//This macro is in included header
#define OBJECT_TYPE(var,class,parent) Object::Type var( #var, parent, &Object::Type::NewFunc<class> )
OBJECT_TYPE(tBob,Bob,NULL);
//And from here, you could optionally assign the type - Not something I want to do repetitively

//New style (already established)
class Bob : public Object::Auto<Bob,"Bob"> { //Not too pretty, but better
//And that's about it
//Objects aren't required to have types (NOTE: this is for a game engine, not scripting), so they can easily inherit
//Major downfalls: Header dependency (stated above), parents HAVE to be defined with similar method, etc
};
//It can also boil down to (using macros)
//DGI is the project namespace
#define DGI_OBJECT(name) class name : public Object::Auto<name,#name>
#define DGI_OBJECT_EX(name,parent) class name : public Object::Auto<name,#name,parent>
//And
DGI_OBJECT(Bob) {
...
};
//Or: class DGI_OBJECT(Bob) ... (adjusting the macro of course)




Thanks for the help!
Once again, sorry I wasn't entirely clear. Wasn't sure what exactly to say.

EDIT:
As for the naming conventions of my private variables, and using virtual methods to retrieve them, I'm still thinking on those. I'm going to change the name, seeing as how it might conflict with a compiler. But on virtuals, maybe or maybe not - the only problem is performance (vtable lookup and such), obviously minute. As I'm typing this, I'm seeing how much better virtuals'll be.
Thanks again!

Share this post


Link to post
Share on other sites

This topic is 4016 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this