C++:如何在地图中使用不同的动态模板

C++: How to use different dynamic template in map

我的header代码:

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

在我的cpp中,我想用一个map来包含不同类型的a,就像下面的代码:

 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);
    }
};

提问:如何实现?

编辑@0410,这是我的解决方案:

class ABase
{
virtual void func(void* t)=0;
}

template <typename T> A;
template <short> A : public ABase
{
    void func(void* t) override
    {
auto value = *static_cast<short*>(t);
// do processing
}
template <float> A : public ABase
{
    void func(void* t) override
    {
auto value = *static_cast<float*>(t);
// do processing
}

CPP:为所有模板使用了 ABase* 映射 class,并为所有模板接口使用了虚函数

main()
{
map<int, ABase*> objs;
objs.insert({0, new A<short>()});
objs.insert({1, new A<float>()});
auto value=0;
objs[0]->func(&value);
auto value1=0.f;
objs[1]->func(&value1);
}

你不能用模板来解决问题。模板声明只是候选类型的蓝图。

“A”是不是“A”本身的类型。

你可以通过继承来解决你的问题。

编辑:代码已根据@MSalters 的评论更新。谢谢

#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;
  } 
};

template<typename T>
class A_Derived : public A
{ 
public: 
  void func(void* x)
  {
    T* value = static_cast<T*>(x);
    std::cout << "[Derived] 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 if(type == 2)
    {
            a.insert({key, new A_Derived<short>()});
    }
    else if(type == 3)
    {
            a.insert({key, new A_Derived<float>()});
    }
        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);
  b.AddA(3, 2);
  b.AddA(4, 3);
  
  
  short s = 1;
  float f = 7.1;
  short s2 = 2;
  float f2 = 7.2;

  b.func(1, &s);
  b.func(2, &f);
  b.func(3, &s2);
  b.func(4, &f2);
}

如果你确实需要在一个地图中有多种类型,你可以使用std::variant的地图。但是正如评论中已经提到的,这可能是一个设计问题。

但是如果你需要的话,你可以继续std::map< int, std::variant<>>。稍后,如果你想访问存储的元素,你必须调用 std::visit 来选择存储在 std::variant.

中的元素

参见以下示例:


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 );
}