1

I have a bunch of classes all inheriting from the same Base class. I'd like to register them in a ClassRegistry which is holds a map of [name=>factoryForThisClass].

To do this I had an idea but it's not working and I don't understand why:

#include <typeinfo>
#include <string>
#include <map>
#include <iostream>

template< typename T >
class declare_type
{
    static int n;
};


struct GenericClassFactory
{
    ~GenericClassFactory() {};
    virtual void* create( const std::string& rstrClassName ) = 0;
};

template <typename T>
struct ClassFactory : public GenericClassFactory
{
    virtual void* create( const std::string& rstrClassName )
    {
        return new T();
    }
};

class ClassRegister
{
public:
    virtual ~ClassRegister()
    {
    }

    template< typename T >
    static int declare( const std::string& rstrClassName = typeid(T).name() )
    {
        std::cout << "ClassRegister::declare( " << rstrClassName << " )\n";
        return 42;
    }

    static void create( const std::string& rstrClassName )
    {
        std::cout << "ClassRegister::create( " << rstrClassName << " )\n";
    }

private:
};

template< typename T >
int declare_type<T>::n = ClassRegister::declare<T>();


template< typename T > 
class BaseClass
{
    declare_type<T> m_declaration;
};

class SomeClass : public BaseClass<SomeClass>
{
public:
    void meow();
};

//template class declare_type<SomeClass>;

int main( void )
{
    ClassRegister::create( "9SomeClass" );

    return 0;
}

in my understanding, having SomeClass inheriting BaseClass<SomeClass> instanciates declare_type<SomeClass> but it doesn't ... note that it does work if I add:

template class declare_type<SomeClass>;

In that case I don't even need the member in BaseClass, but it is a lot less "magic" as there is one such line to write for each class to declare ....

P.S: to be clear "it doesn't work" means ClassRegister::declare() is never called, as opposed to "it works" meaning ClassRegister::declare() is called before main and I can use the ClassRegistry properly.

P.S.2: OK: http://ideone.com/Af49Pb KO: http://ideone.com/ZMSSJW, only diff is line 66

foke
  • 1,339
  • 2
  • 12
  • 20
  • 3
    you say it "doesn't work", but what is actually happening? Do you get errors? Which ones? What unexpected things happen? – sth Jun 24 '14 at 15:58
  • may be duplicate with this: http://stackoverflow.com/questions/1819131/c-static-member-initalization-template-fun-inside – Matt Jun 24 '14 at 16:05
  • 3
    Not a solution, but if you have a "factory" design pattern in a strongly-typed language like C++ that returns `void *` you may have some inherent flaws in your design. – 0xbe5077ed Jun 24 '14 at 16:08
  • We are eager to solve this mystery. Our team of highly trained monkeys is doing its best putting back all the code you have omitted in order to achieve the level zero intermediate goal: make the bloody thing compile. Expected delivery date is somewhere after the World Cup (hopefully the current one) ends. – n. m. could be an AI Jun 24 '14 at 16:29
  • @sth "doesn't work" means ClassRegister::declare never gets called. – foke Jun 24 '14 at 16:34
  • @n.m. the omitted code is never called, that's the issue so it isn't relevant – foke Jun 24 '14 at 16:34
  • 1
    Oh, I see. You are using *Visual Studio*. The bloody thing is not meant to be compilable with normal compilers. My bad. – n. m. could be an AI Jun 24 '14 at 16:39
  • @0xbe5077ed you're right but it's just a quick test, in the real project I intend to use it on it won't work like this – foke Jun 24 '14 at 16:40
  • Re. compilation in VS vs compilation elsewhere: VC++ template implementation is broken and lets you get away with invalid code. You need to move the definition of `declare_type::n` below declaration of `ClassRegister::declare` for standards compliance. – n. m. could be an AI Jun 24 '14 at 16:54
  • alrigth I've made it compile on ideone, which is using gcc, so all remarks on vs or the fact that the provided code doesn't compile are now void – foke Jun 24 '14 at 17:19

1 Answers1

0

You explicitly instantiate declare_type<SomeClass>, but this means absolutely nothing for declare_type<SomeClass>::n. It is not used, and thus will not be instantiated.

If you want it to be instantiated, you need to use it, directly or indirectly, from non-template code.

int doit = declare_type<SomeClass>::n;

(you need to make n public of course).

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243