Search code examples
c++templatesc++14non-statictemplate-variables

non-static template member : possible?


Is it possible to create non-static template field in a class?
If no, how to workaround?

Such fields should be created at compile time as needed.

Example

I have a lot of B-class, like B1,B2,B3.
(In real case, they have more meaningful names.)

I want to create a class D that has non-static template function add<BX>() that have to counter++ every time I call it, for each individual BX, for a certain instance of D.
(In real case, it does somethings more complex.)

Here is a working demo to achieve it.
Sadly, I currently have to hard-code every BX, one-by-one (B1,B2,B3) inside D :-

class B1{};class B2{};class B3{};
class Counter{
    public: int counter=0;
};
template<class BX>class Tag{};
class D{
    Counter countB1;
    Counter countB2;
    Counter countB3;
    public: template<class BX> void add(){  
        add_(Tag<BX>());
    }
    private:
    void add_(Tag<B1>){ countB1.counter++;}
    void add_(Tag<B2>){ countB2.counter++;}
    void add_(Tag<B3>){ countB3.counter++;}
    public: template<class BX> int get(){
        return get_(Tag<BX>());
    }
    private:
    int get_(Tag<B1>){  return countB1.counter;}
    int get_(Tag<B2>){  return countB2.counter;}
    int get_(Tag<B3>){  return countB3.counter;}
};

Here is the usage. Notice that each instance of D keep its own counter :-

int main() {
    D d1;
    d1.add<B2>();   d1.add<B2>();   d1.add<B3>();
    std::cout<<d1.get<B1>()<<" "<<d1.get<B2>()<<" "<<d1.get<B3>()<<"\n";
    //^ print 0 2 1  
    D d2;
    d2.add<B1>();
    std::cout<<d2.get<B1>()<<" "<<d2.get<B2>()<<" "<<d2.get<B3>()<<"\n";
    //^ print 1 0 0  (not 1 2 1)
    return 0;
}

I dream for something like :-

class D{
    Counter<BX> countBX; //???
    public: template<class BX> void add(){  
         Counter<BX>::getNonStaticInstance(this).counter++; //???
    }
    public: template<class BX> int get(){
        return Counter<BX>::getNonStaticInstance(this).counter; //???
    }
};

I know how to do it if countBX is static, but for non-static it seems to be impossible.


Solution

  • Using a std::map std::unordered_map (suggestion from Yakk; thanks) of indexes and RTTI?

    #include <map>
    #include <iostream>
    #include <typeindex>
    
    class B1 {};
    class B2 {};
    class B3 {};
    
    class D
     {
       private:
          std::unordered_map<std::type_index, std::size_t> bxMap;
    
       public:
          template <typename BX>
          void add ()
           { ++ bxMap[std::type_index(typeid(BX))]; }
    
          template <typename BX>
          int get ()
           { return bxMap[std::type_index(typeid(BX))]; }
     };
    
    int main ()
     {
       D d1;
       d1.add<B2>();    d1.add<B2>();   d1.add<B3>();
       std::cout<<d1.get<B1>()<<" "<<d1.get<B2>()<<" "<<d1.get<B3>()<<"\n";
       //^ print 0 2 1
       D d2;
       d2.add<B1>();
       std::cout<<d2.get<B1>()<<" "<<d2.get<B2>()<<" "<<d2.get<B3>()<<"\n";
       //^ print 1 0 0
       return 0;
     }