Counting template classes at compile time

P

Patrick Kowalzick

Dear all,

I just wondered if it is possible to count the number of classes created via
a template class at compile time.

To show what I mean I post an example, which is not working but carries the
idea:

static int counter = 0; // this variable can be changed only at runtime...
template <typename T> struct want_to_be_counted;
{
static const int help_counting = counter++; // so this is always 0 (or
even better undefined?)
};

Each time when the compiler creates class with a new type, it shall
increment a variable.

want_to_be_counted< int > ----> counter = 1;
want_to_be_counted< float > ----> counter = 2;
want_to_be_counted< int > ----> counter = still 2;

Any ideas or hints where to read? Thank you,
Patrick
 
V

Victor Bazarov

Patrick said:
I just wondered if it is possible to count the number of classes created via
a template class at compile time.

Why would anybody care about that? Why do _you_ care? How would you
use the counter value if it were available?
To show what I mean I post an example, which is not working but carries the
idea:

static int counter = 0; // this variable can be changed only at runtime...
template <typename T> struct want_to_be_counted;
{
static const int help_counting = counter++; // so this is always 0 (or
even better undefined?)

Static members of templates are not instantiated until they are used.
So, you have to use that member in order to cause its instantiation.
};

Each time when the compiler creates class with a new type, it shall
increment a variable.

want_to_be_counted< int > ----> counter = 1;
want_to_be_counted< float > ----> counter = 2;
want_to_be_counted< int > ----> counter = still 2;

Any ideas or hints where to read? Thank you,

I don't think it's possible. Instantiation of a template is a compile-
time activity, and any particular template can be instantiated in more
than one compilation unit, the compiler cannot really keep track of
anything across compilation units, now, can it?

Victor
 
P

Patrick Kowalzick

Hello Victor,

thanks for your response.
Why do _you_ care? How would you
use the counter value if it were available?

Sorry long answer, but you asked why _I_ would care ;).

I am searching a neat possibility to do some multi-dispatching. My
dispatcher right now has some disadvantages and I am trying to correct some
small things and learn about other possibilities. An example for my
implementation later.

I know that Andrei Alexandrescu has developed a very nice one for LOKI, but
there are some reasons why I do not use it. One reason is that I do not want
to use this library (what reasons ever). Besides that it would need too much
adaption to really fit it for my purpose. The best fitting scheme would be
the brute force solution.

Anyway, I want to avoid to put inside the classes the dispatching via
chained calls of virtual functions to keep the orthogonality of my design.
(Similar to Andrei's solution).

Furthermore I want to avoid the RTTI stuff, because in my case I can use
real brute force routines. I know all the branches needed in advance. I use
a switch because it is much faster then nested if's (sure, depending on the
number of classes/combinations) .

An example might look like this:

#include <iostream>
#include <vector>

// forward declaration
struct A;
struct B;

// definig a class with an ID inside to
// avoid the RTTI-processes
template <typename> struct CID;

template <> struct CID<A>
{
static const int ID = 0;
};

template <> struct CID<B>
{
static const int ID = 1;
};

// The class hierachy
struct BASE {
virtual const int ID() = 0;
virtual ~BASE() {}
};

struct A : public BASE
{
void calling() {
std::cout << "A calling" << std::endl;
}
virtual const int ID() {
return CID<A>::ID;
}
};

struct B : public BASE
{
void calling() {
std::cout << "B calling" << std::endl;
}
virtual const int ID() {
return CID<B>::ID;
}
};

// this is an example why I do not like this approach
// for each T i MUST provide the corresponding CID< C<T> >
template <typename T>
struct C : public BASE
{
void calling() {
std::cout << "B calling" << std::endl;
}
virtual const int ID() {
return CID< C<T> >::ID;
}
};

int main()
{
// create collection
std::vector< BASE * > vec;
vec.push_back( new A() );
vec.push_back( new B() );
vec.push_back( new B() );
vec.push_back( new A() );

// example for single dispatch
for (unsigned int i = 0; i < vec.size(); ++i)
switch( vec->ID() )
{
// using here some (not-)nice Makro tricks
case( CID<A>::ID ) :
static_cast<A *>( vec )->calling();
break;
case( CID<B>::ID ) :
static_cast<B *>( vec )->calling();
break;
default :
std::cerr << "Something is wrong...." << std::endl;
}

// cleanup when virtual dtor, otherwise switchtable again
for (unsigned int i = 0; i < vec.size(); ++i) delete vec;

return 0;
}

Each class put in the dispatcher must have an ID, accessible via a virtual
call. So far no problem, but coming back to my OP. I wanted to get a class
CID<T> returning a unique ID for each class - automatically:

template <typename T> struct CID;
{
static const int ID = unique_ID<T>();
};

It is similar to a type_info but returning something what could be used
easily in a switch statement.

to count the different class types, seemed one solution to me. Anyway it
would be nice to get them in order, for a better efficiency of the switch.
I don't think it's possible. Instantiation of a template is a compile-
time activity, and any particular template can be instantiated in more
than one compilation unit, the compiler cannot really keep track of
anything across compilation units, now, can it?

IMO no problem here.

Regards,
Patrick
 
V

Victor Bazarov

Patrick said:
Why do _you_ care? How would you
use the counter value if it were available?


Sorry long answer, but you asked why _I_ would care ;).

[...]
It is similar to a type_info but returning something what could be used
easily in a switch statement.

Why does it have to be a switch statement? Couldn't it be, say,
a 'map<whatever, function_pointer>'? 'whatever' could be a string
or something else.

The bottom line is that if you relax the requirement to do it in
compile-time and allow it to be done in run-time, you could get
more and easier solutions.
[...]
I don't think it's possible. Instantiation of a template is a compile-
time activity, and any particular template can be instantiated in more
than one compilation unit, the compiler cannot really keep track of
anything across compilation units, now, can it?


IMO no problem here.

I don't understand your "no problem here" statement.

Victor
 
P

Patrick Kowalzick

Dear Jonathan,
See the thread "instantiation_count (was: is_incomplete)" from the Boost
developers list.

http://lists.boost.org/MailArchives/boost/msg37791.php

this was exactly what I was searching for. I searched the actual boost but
can not find an actual version of "instantiation_count" or "is_incomplete".
Together with the discussion in the thread mentioned, I believe there is not
yet a tidy solution.

So I will discard this idea for now.

Thanks a lot,
Patrick
 
P

Patrick Kowalzick

Hello Victor
Why does it have to be a switch statement? Couldn't it be, say,
a 'map<whatever, function_pointer>'? 'whatever' could be a string
or something else.

It must not be a switch, and I will keep in mind that a map might be a
possible solution to replace a switch.

In this case "whatever" should be a type_info (or the string name out of
typeinfo), what IMO is the only unique "feature" for any class. It seems
quite expensive to me to carry around the type_info so I would prefer, e.g.
an int. With an int I could use either switch, map (Alexandrescus
BasicDispatcher) or vector (Alexandrescus BasicFastDispatcher).

I did not test yet, but with map it should be _possible_ to use the
type_info (oh - I have to look if it is comparable). Anyway, all the
structures mentioned above must be 2D for double-dispatching, means
nested-ifs, nested switch/if, 2D-map or 2D-vector/matrix.
The bottom line is that if you relax the requirement to do it in
compile-time and allow it to be done in run-time, you could get
more and easier solutions.

This indeed might be true, but like described in my OP I reduce it to
"how-to get a unique ID", what is independent which structure to take.
Alexandrescu for example is defining a macro which must be included in each
class dispatched by the BasicFastDispatcher to define this ID.

// Andrei Alexandrescus Macro
#define IMPLEMENT_INDEXABLE_CLASS(SomeClass) \
static int& GetClassIndexStatic() \
{\
static int index = -1;\
return index;\
}\
virtual int& GetClassIndex()\
{\
assert(typeid(*this) == typeid(SomeClass));\
return GetClassIndexStatic();\
}

The variable index is used to indicate if the class was used in a dipatcher
and if, which slot was used. This is working quite nice and putting together
a single-dispatcher could look like this:

template <typename T>
void Add(std::vector<void(*)(const BASE &)> & callbacks)
{
int& index = T::GetClassIndexStatic();
if (index < 0) index = callbacks.size(); // define slot where to go
if ( callbacks.size() < index + 1 ) callbacks.resize( index + 1 ); //
assure that vector is big enough
void(* fooT)( const T & ) = foo;
callbacks[index] = (void(*)(const BASE &))fooT;
}

//the calls somewhere

std::vector<void(*)(const BASE &)> callbacks;

Add<A>(callbacks);
Add<B>(callbacks);

for (unsigned int i = 0; i < vec.size(); ++i)
{
callbacks[vec->GetClassIndex()](*vec);
}


So I still search a solution to define an ID, but I think I will refine
Alexandrescus method and adopt it to my needs.

Thanks,
Patrick
 
J

Jonathan Turkanis

Patrick Kowalzick said:
Dear Jonathan,


this was exactly what I was searching for. I searched the actual boost but
can not find an actual version of "instantiation_count" or "is_incomplete".
Together with the discussion in the thread mentioned, I believe there is not
yet a tidy solution.

I think the consensus was that it's not possible with a standard-conforming
compiler.

Jonathan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top