From: GH on
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
> 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
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
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
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! ]