User defined class meta data (type traits?)

G

greek_bill

Hi,

I'm trying to develop a system where I can register some data/
information about a class. For example

// ClassInfo.h
template <class T>
struct ClassInfo
{
static const std::string tagName;
static const int version;
static const bool isConfigurable;
};

// FooBar.h
class FooBar {...};

// FooBar.cpp
template<> const std::string ClassInfo<FooBar>::tagName = "FooBar";
template<> const int ClassInfo<FooBar>::version = 1;
template<> const bool ClassInfo<FooBar>::isConfigurable = false;

// main.cpp
....
#include "FooBar.h"
if (ClassInfo<FooBar>::isConfigurable)
{...}

This does what I originally wanted, which is to allow me to associate
meta-data with some arbitrary class, and have that accessible
throughout the code.

The problem is that since the above relies on static variables being
initialized at runtime, I cannot use any of the data as template
arguments. For example I'd like to be able to do the following :


template<class T, bool isConfigurable>
struct SomeAlgorithmImp
{
static void Func()
{
//...
};
};

template<class T>
struct SomeAlgorithmImp<T, true>
{
static void Func()
{
//...
};
};

template<class T>
struct SomeAlgorithm
{
static void Func()
{
SomeAlgorithmImp<T, ClassInfo<T>::isConfigurable>::Func();
}
};

SomeAlgorithm<FooBar>::Func();


The problem is that ClassInfo<T>::isConfigurable is not a 'compile
time constant expression'. (it actually can be used as a template
argument but only in the same translation unit as the definition of
the static variable - which limits its usefulness).

Any ideas on how I might be able to achieve this?

At some point I naively thought I can put the following in the header
instead of the translation unit :

template<> const bool ClassInfo<FooBar>::isConfigurable = false;

which of course works for using it as a template argument, but also
gives you multiple symbols during linking (yet bizarrely VC8 doesn't
seem to mind, g++ does).

I also tried making the ClassInfo class contain a struct which is
redifined per 'T', e.g.

template<class T>
struct ClassInfo
{
struct IsConfigurable;
};

then :
template<>
struct ClassInfo<Foo>::IsConfigurable
{
enum { Value = 1 };
};

This would have almost worked...had it not been for namespaces.
ClassInfo<T>::IsConfigurable must be defined in the same namespace as
ClassInfo...which in my case is impossible to guarantee.

I could also override the entire contents of ClassInfo. this would let
me to initialize integral types (like the int and bool members above)
within the class body thus avoiding the linker errors. However, this
approach also suffers from the namespace issues (the specialization of
a class must be in the same namespace as the class template itself)
(another thing that VC8 isn't too fussed about either!)

Any other ideas? At the moment I'm leaning towards trying to work
around my design's namespace complications , which would allow me to
use the child struct method above. Either that, or just go with a run
time solution to keep things simple.

Many thanks,

Bill
 
A

anon

greek_bill said:
Hi,

I'm trying to develop a system where I can register some data/
information about a class. For example

// ClassInfo.h
template <class T>
struct ClassInfo
{
static const std::string tagName;
static const int version;
static const bool isConfigurable;
};

// FooBar.h
class FooBar {...};

// FooBar.cpp
template<> const std::string ClassInfo<FooBar>::tagName = "FooBar";
template<> const int ClassInfo<FooBar>::version = 1;
template<> const bool ClassInfo<FooBar>::isConfigurable = false;

// main.cpp
...
#include "FooBar.h"
if (ClassInfo<FooBar>::isConfigurable)
{...}

This does what I originally wanted, which is to allow me to associate
meta-data with some arbitrary class, and have that accessible
throughout the code.

[...]

Does the next example demonstrates what you want?

#include <string>
#include <iostream>

struct A1
{
};
struct A2
{
};

template < class T >
struct At
{
};

template<>
struct At< A1 >
{
static std::string Get()
{
return "A1";
}
};
template<>
struct At< A2 >
{
static std::string Get()
{
return "A2";
}
};
int main()
{
std::cout << At< A1 >::Get() << std::endl;
}
 
G

greek_bill

Does the next example demonstrates what you want?

No, not really. What you're doing is overriding (or rather providing)
Get() in a template specialization and the use that at run time. What
I'd like to do is override/provide something (e.g. an int or a bool)
in a template specialization and use that as a template argument at
compile time.
 
G

greek_bill

I like the partial base class specialization...good idea! :)

but I think it suffers from the same namespace problems. In my setup I
have something like :

namespace Core
{
// ClassInfo template definition here
}

namespace Extension
{
class Foo;

// Ideally I'd like to have the Foo specialization here
template<> ClassInfo<Foo> { ... };
}

The above fails to compile because the specialization of ClassInfo
appears in a different namespace ('Extension') than its definition. To
get this to work, I'd have to have the following :

namespace Extension
{
class Foo;
}

namespace Core
{
template<> ClassInfo<Extension::Foo> { ... };
}

While this is certainly possible, it forces a code layout restriction
that I'm not comfortable with. Ideally I'd like to keep the
specialization on Foo and Foo's definition as close as possible.

I admit, this isn't a huge problem, but if I could work around it that
I'd rather I did!


btw, I've moved on from this. What I did in the end is to 'discover'
whether a class is 'configurable' by checking for the presence of a
certain function. I find that discovering existing features (traits?)
of a class is generally easier than associating new ones (like I've
been describing above). Most of the relevant material I've read on
this topic (Modern C++, Boost::type_traits, etc) focus on discovering
features about a class.

Also, as it turns out, in my case it's better to decide whether a
class is configurable based on the presence of a Configure() function.
While I was trying to get the bool 'IsConfigurable' to work, I found
myself adding a static check (compile time assert) to ensure that if a
class is declared as configurable then it also provides a configure
function.

Anyway, thanks for the good idea though! :)
Compile-time traits are a great tool. :)

Yes, they are!

Bill
 

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,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top