Home > Net >  C : How to use different dynamic template in map
C : How to use different dynamic template in map

Time:04-07

my header code:

template <typename T>
    class A
    {
    
    }
    
    template<> class A<short>;
    template<> class A<float>;

in my cpp, i want to use a map to contain different type a, like following code:

 class B
{
    map<int, A*> a; /* how to declare a */
public:
    AddA(int key, int type)
    {
        if (type == 1)
        {
            a.insert({ key, new A<short>() });
        }
        else
        {
            a.insert({ key, new A<float>() });
        }
    }
    template<typename T>
    func(int key, T v)
    {
        a[key].func(v);
    }
};

question: how to implement it?

CodePudding user response:

You can't achieve the problem with templates. Template declaration is only a blueprint for a type candidate.

"A<short>" is the type not "A" itself.

You can achieve your problem through inheritance.

#include <iostream>
#include <map>

class A 
{
public:
  virtual void func(void* x) = 0;
};

class A_Short : public A
{ 
public: 
  void func(void* x)
  {
    short* value = static_cast<short*>(x);
    std::cout << "short value: " << *value << std::endl;
  } 
};

class A_Float  : public A
{ 
public: 
  void func(void* x)
  {
    float* value = static_cast<float*>(x);

    std::cout << "float value: " << *value << std::endl;
  } 
};

class B
{
    std::map<int, A*> a; /* how to declare a */
public:
    void AddA(int key, int type)
    {
        if (type == 1)
        {
            a.insert({ key, new A_Short() });
        }
        else
        {
            a.insert({ key, new A_Float() });
        }
    }

    // Assumes that user knows to use which T for any "key"
    template<typename T>
    void func(int key, T v)
    {
        a[key]->func(v);
    }
};


int main()
{
  B b;

  b.AddA(1, 1);
  b.AddA(2, 8);
  
  short s = 4;
  float f = 7.2;
  b.func(1, &s);
  b.func(2, &f);
}

CodePudding user response:

If you really need to have multiple types in a single map, you can use a map of std::variant. But as already mentioned in the comments, this might be a design problem.

But if you need it, you can proceed with the std::map< int, std::variant<>>. Later on, if you want to access the stored element, you have to call std::visit to pick the element which is stored in std::variant.

See the following example:


template < typename T >
struct A
{
};

// spezialize if needed, here only for demonstration purpose
template <> struct A<short> { void func(short parm) { std::cout << "A<short> with " << parm << std::endl; } }; 
template <> struct A<float> { void func(float parm) { std::cout << "A<float> with " << parm << std::endl; } }; 


class B
{
    std::map<int, std::variant<A<short>*, A<float>*>> a; 
    public:
    void AddA(int key, int type)
    {    
        if (type == 1)
        {
            a.insert({ key, new A<short>() });
        }
        else
        {
            a.insert({ key, new A<float>() });
        }
    }    
    template<typename T>
        void func(int key, T v) 
        {
            std::visit( [&v]( auto ptr ) { ptr->func(v); }, a[key] );
        }
};

int main()
{
    B b; 
    b.AddA( 1, 1 ); 
    b.AddA( 2, 2 ); 

    b.func( 1, 99 );
    b.func( 2, 100 );
}
  • Related