Prev: Converting from int** to vector< vector<int> >&
Next: how to pass polymorphic container classes
From: GH on 20 May 2010 12:31 Thanks to all for the reply. Here is my original problem. I'm writing a family of base classes, each with a unique id, and each to be derived at most once. This is what I have in mind: template<unsigned int id> class Base { // ... }; The Base provides common features to all. Each client class is to derive from one instantiation of Base. I'd like to enforce that no two classes derive from the same instantiation. It is not hard to do at run time. But a compile time check is better. Thanks again for all the reply. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: TJorgenson on 22 May 2010 04:05 > Here is my original problem. I'm writing a family of base classes, > each with a unique id, and each to be derived at most once. This is > what I have in mind: > > template<unsigned int id> > class Base > { > // ... > > }; > > The Base provides common features to all. Each client class is to > derive from one instantiation of Base. I'd like to enforce that no two > classes derive from the same instantiation. It is not hard to do at > run time. But a compile time check is better. You didn't mention that your base was a template in your original post... If all of your derived classes are specializations of the same class template (i.e. the same class template name) then you could pass the "id" template parameter from the derived to the base. Then in your base class you could make the derived class template specialization a friend and your base class constructor private to guarantee the 1 to 1 relationship as follows: template<unsigned int id> class Derived; template<unsigned int id> class Base { Base() {}; // <== constructor is private. friend class Derived< id >; // <== Only class template "Derived" with same id can inherit. }; template<unsigned int id> class Derived : public Base< id > { Derived() {}; // This prevents instantiation except for specializations // with public constructor. }; template<> class Derived< 1 > { // Default compiler generated constructor is public. }; template<> class Derived< 2 > { // Default compiler generated constructor is public. }; class D4 : public Base< 4 > // <== this compiles on VCPP, // but can't be instantiated (see below). { }; int main() { Derived< 1 > d1; Derived< 2 > d2; // Derived< 3 > d3; // <== this does not compile (no specialization with id==3). // D4 d4; // <== this does not compile (Base constructor is private). } Still not sure if you really want to do this, but maybe this does what you want. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: itaj sherman on 23 May 2010 03:48 On May 19, 5:04 am, GH <yzg...(a)gmail.com> wrote: > Is there any way at compile time to restrict direct inheritance from a > class to no more than once? Thanks for any insight. > You didn't tell much about the structure of your clients, so it's hard to know what restrictions you can accept. Other suggestion required the server code will have to include a forward declaration of the classes / template class of the clients. I have here other options with other restrictions. Really, what are you using this for? Is it to assist debbugging, serialization? Does the unique ID of each client have to stay the same forever (in all executions / future compilations / after code changes)? On a side comment, does the client really have to inherit the server class type, or you just need each client to be using (be assigned to) a separate instantiation of Base<>? This doesn't much affects the rest of my answer though. I would consider changing the template parameter of Base to a type (rather than int). Then having each client define a separate class (not used by other clients), and use Base< MyClientIDClass >. If each has a defined class (or template instanciation) you can use that. class MyClient { //using or deriving Base< MyClient > .... }; Otherwise, you could use GUID (globally unique ID) like: class GUID_f2fefb001bed11df97c30002a5d5c51b {}; typedef GUID_f2fefb001bed11df97c30002a5d5c51b MyClientID; class MyClient { //using or deriving Base< MyClientID > .... }; Now, if some parts of the application need to have a unique integer representation for the ID of each client, then you could maintain a static container that will assign integer numbers to each instantiation of Base< Type >, based on the lexical ordering of std::string(typeid(Type).name()). In this case, if you used the client type itself, the integers will be kept as long as the names of the client classes don't change. If you used the GUID classes, then new clients added to the code will have bigger integer ID (assure GUID lexical order increases with time). Another option is, if possible, to have a single location in the code that can include the definitions of all clients like in a type-list. Then it's possible to design a template that will MPL verify that each client uses a different instantiation of Base<>. class boost::mpl::type_list< ClientA, ClientB, ClientC .... > AllClients; template class VerifySeparateClientID< AllClients >; //template instantiation itaj -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Nick Hounsome on 25 May 2010 01:37 On 21 May, 04:31, GH <yzg...(a)gmail.com> wrote: > Thanks to all for the reply. > > Here is my original problem. I'm writing a family of base classes, > each with a unique id, and each to be derived at most once. This is > what I have in mind: > > template<unsigned int id> > class Base > { > // ... > > }; > > The Base provides common features to all. Each client class is to > derive from one instantiation of Base. I'd like to enforce that no two > classes derive from the same instantiation. It is not hard to do at > run time. But a compile time check is better. This can never be done at compile time because the compiler doesn't know about other compilation units. The only tool that knows is the linker. At first I thought that one way to do it would be to declare a static member in Base, maybe a count of instances incremented in the ctor. If you then require each derived class to actually define the appropriate Base member in it own cpp file then the linker would catch multiple definitions. Unfortunately my tests with VS2010 show that the linker treats all the definitions as the same even when they are not. This seems wrong to me but I'm not a language lawyer (Of course it works for non-template classes). You could always do the check yourself by examining the symbols in the object files using nm,sort and grep on unix (on windows it's harder). Another thought is that sometimes it's best to turn the problem on its head and generate code from a list of the derived class names. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: itaj sherman on 25 May 2010 03:56 On May 23, 9:48 pm, itaj sherman <itajsher...(a)gmail.com> wrote: > On May 19, 5:04 am, GH <yzg...(a)gmail.com> wrote: > > I would consider changing the template parameter of Base to a type > (rather than int). Then having each client define a separate class > (not used by other clients), and use Base< MyClientIDClass >. If each > has a defined class (or template instanciation) you can use that. > > class MyClient > { > //using or deriving Base< MyClient > > ... > > }; > > Otherwise, you could use GUID (globally unique ID) like: > > class GUID_f2fefb001bed11df97c30002a5d5c51b {}; > > typedef GUID_f2fefb001bed11df97c30002a5d5c51b MyClientID; > class MyClient > { > //using or deriving Base< MyClientID > > ... > > }; > > Now, if some parts of the application need to have a unique integer > representation for the ID of each client, then you could maintain a > static container that will assign integer numbers to each > instantiation of Base< Type >, based on the lexical ordering of > std::string(typeid(Type).name()). In this case, if you used the client > type itself, the integers will be kept as long as the names of the > client classes don't change. If you used the GUID classes, then new > clients added to the code will have bigger integer ID (assure GUID > lexical order increases with time). > I want to make clear, this suggestion does the uniqueness checking at compile time, only the conversion of the ID class into an integer is at runtime (if at all needed). That beside the other restrictions I mentioned. itaj -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Pages: 1 2 Prev: Converting from int** to vector< vector<int> >& Next: how to pass polymorphic container classes |