C++ 如何根据使用模板的类型将元素添加到各种容器中

C++ 如何根据使用模板的类型将元素添加到各种容器中,c++,templates,C++,Templates,我有一个相当愚蠢的问题,但我希望你能帮我解决这个问题 我有一个有多个向量的类,这个向量有不同的存储类型 class BaseClass{ std::string Name; } class B : public BaseClass{ } class C : public BaseClass{ } class A{ vector<std::pair<std::string, B>> V1; vector<std::pair<std::stri

我有一个相当愚蠢的问题,但我希望你能帮我解决这个问题

我有一个有多个向量的类,这个向量有不同的存储类型

class BaseClass{
  std::string Name;
}

class B : public BaseClass{

}
class C : public BaseClass{

}

class A{
  vector<std::pair<std::string, B>> V1;
  vector<std::pair<std::string, C>> V2;
}
类基类{
std::字符串名;
}
B类:公共基类{
}
C类:公共基类{
}
甲级{
向量V1;
矢量V2;
}
在我的类A中有一个模板函数,用于向该向量添加元素:

template <class T>  void addElement(T Obj);
模板无效补遗(T Obj);
我希望这种情况发生:

A a;
B b;
C c;


a.addElement<B>(b) -> then element b is added to vector V1
a.addElement<C>(c) -> then element c is added to vector V2
A;
B B;
C C;
a、 addElement(b)->然后将元素b添加到向量V1
a、 addElement(c)->然后将元素c添加到向量V2
我想出了这样的办法:

template <class T>  void addElement(T Obj){
  std::pair<std::string, T> AddedPair(Obj.Name, Obj);

   if (typeid(T) == typeid(B)) 
    V1.push_back(AddedPair);

   if (typeid(T) == typeid(C)) 
    V2.push_back(AddedPair);

}
模板无效补遗(T Obj){
std::成对添加的空气(Obj.Name,Obj);
if(typeid(T)=typeid(B))
V1.推回(添加空气);
if(typeid(T)=typeid(C))
V2.推回(添加空气);
}
但不幸的是,这段代码无法编译,因为不知何故,模板是作为一个整体编译的,如果我使用B作为模板参数,那么编译器无法将B转换为C,尽管程序永远不会达到这种转换发生的程度:(

你对我如何解决这个问题有什么建议吗?我会非常感激的。

而不是

template <class T>  void addElement(T Obj);
这将为您节省专门化模板或需要C++17的所有语法,并在编译时做出决策


原因

template <class T>  void addElement(T Obj){
std::pair<std::string, T> AddedPair(Obj.Name, Obj);

    if (typeid(T) == typeid(B)) 
        V1.push_back(AddedPair);

    if (typeid(T) == typeid(C)) 
        V2.push_back(AddedPair);

}
如果constexpr,则使用

template <class T>  void addElement(T Obj){
std::pair<std::string, T> AddedPair(Obj.Name, Obj);

    if constexpr(std::is_same_v<T, B>) 
        V1.push_back(AddedPair);

    if constexpr(std::is_same_v<T, C>) 
        V2.push_back(AddedPair);

}       
模板无效补遗(T Obj){
std::成对添加的空气(Obj.Name,Obj);
如果constexpr(std::is_same_v)
V1.推回(添加空气);
如果constexpr(std::is_same_v)
V2.推回(添加空气);
}       

如果像这样使用共享基类会怎么样?? 您必须为基类创建一个公共接口,但我不确定B和C在功能方面会有多大不同

class BaseClass{
public:
    std::string Name;
};

class B : public BaseClass{
};
class C : public BaseClass{
};

class A{
public:
    std::vector<std::pair<std::string, std::unique_ptr<BaseClass>> > V1;
    std::vector<std::pair<std::string, std::unique_ptr<BaseClass>> > V2;

    template <class T>  void addElement(T Obj)
    {

        std::pair<std::string, std::unique_ptr<T>> AddedPair(Obj.Name, std::make_unique<T>(Obj));

        if (typeid(T) == typeid(B)) 
            V1.push_back(AddedPair);

        else if (typeid(T) == typeid(C)) 
            V2.push_back(AddedPair);
    }  
};

int main()
{
  A a;
  B b;
  C c;

  a.addElement<B>(b) ;//-> then element b is added to vector V1
  a.addElement<C>(c) ;//-> then element c is added to vector V2
}
类基类{
公众:
std::字符串名;
};
B类:公共基类{
};
C类:公共基类{
};
甲级{
公众:
std::向量V1;
std::向量V2;
模板无效补遗(T Obj)
{
std::pair AddedPair(Obj.Name,std::make_unique(Obj));
if(typeid(T)=typeid(B))
V1.推回(添加空气);
否则,如果(类型ID(T)=类型ID(C))
V2.推回(添加空气);
}  
};
int main()
{
A A;
B B;
C C;
a、 addElement(b);//->然后将元素b添加到向量V1
a、 addElement(c);//->然后将元素c添加到向量V2
}

这可能是a的一个用例。它使按关联类型索引容器成为可能。因此,处理几十个类似的
向量V1;
字段的代码变得通用:

#include <vtt/container/Tagged Tuple.hpp>

#include <string>
#include <type_traits>
#include <vector>
#include <utility>

class BaseClass{::std::string Name;};
class B : public BaseClass{};
class C : public BaseClass{};

class A
{
    public: template<typename x_Item> using
    t_Vector = ::std::vector<::std::pair<::std::string, x_Item>>;

    public: using
    t_Vectors = ::n_vtt::n_container::t_TaggedTuple
    <// index type -> value type mapping
        B, t_Vector<B>
    ,   C, t_Vector<C>
    >;

    private: t_Vectors m_vectors;

    public: template<typename x_Item> void
    Add_Item(x_Item && item)
    {
        m_vectors
            // invoke either Get_MutableItem<B> or Get_MutableItem<C>
            .Get_MutableItem<::std::remove_reference_t<::std::remove_cv_t<x_Item>>>()
            // add item into corresponding std::vector
            .emplace_back(::std::string{}, ::std::forward<x_Item>(item));
    }
};

int main()
{
    A a;
    a.Add_Item(B{});
    C c{};
    a.Add_Item(c);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
类基类{::std::string Name;};
B类:公共基类{};
C类:公共基类{};
甲级
{
公共:模板使用
t_Vector=::std::Vector;
公众:使用
t_Vectors=::n_vtt::n_container::t_TaggedTuple
值类型映射
B、 t_向量
,C,t_向量
>;
私有:t_向量m_向量;
公共:模板无效
添加项目(x项目和项目)
{
m_向量
//调用Get_MutableItem或Get_MutableItem
.Get_MutableItem()
//将项添加到相应的std::vector中
.emplace_back(::std::string{},::std::forward(项));
}
};
int main()
{
A A;
a、 增加项目(B{});
C{};
a、 增加第(c)项;
返回0;
}
您可以对向量使用“通用getter”:

class A
{
public:

    template <typename T>
    std::vector<std::pair<std::string, T>>& getVector() {
        auto vectors = std::tie(V1, V2);
        return std::get<std::vector<std::pair<std::string, T>>&>(vectors);
    }

    template <class T>
    void addElement(T Obj) {
        getVector<T>().emplace_back(Obj.Name, Obj);
    }

    std::vector<std::pair<std::string, B>> V1;
    std::vector<std::pair<std::string, C>> V2;
};

如果您打算在几个地方使用向量,您可以专门使用一个模板来获得正确的向量,那么您的主模板代码可以是通用的:

class A{
public:

  template < typename T >
  void addElement(T obj)
  {
    getVector<T>().push_back(std::make_pair(obj.Name,obj));
  }

  template < typename T >
  T& getElement(size_t index)
  {
    return getVector<T>().at(index).second;
  }

private:
  vector<std::pair<std::string, B>> V1;
  vector<std::pair<std::string, C>> V2;

  template < typename T >
  vector<std::pair<std::string, T>>& getVector();
};

template <>
vector<std::pair<std::string, B>>& A::getVector<B>() { return V1; }
template <>
vector<std::pair<std::string, C>>& A::getVector<C>() { return V2; }
A类{
公众:
模板
无效附加元素(T obj)
{
getVector().push_back(std::make_pair(obj.Name,obj));
}
模板
T&getElement(大小索引)
{
返回getVector().at(index).second;
}
私人:
向量V1;
矢量V2;
模板
vector&getVector();
};
模板
vector&A::getVector(){return V1;}
模板
vector&A::getVector(){return V2;}

查找模板专用化和SFINAE。只需创建具有不同类型的函数重载。这不是真正的泛型。如果我将类型D传递给它会发生什么情况,但将有15-20种不同类型的向量,不仅是B、C,所以我不想创建15-20个重载函数:/事实上,可能会有同样多的代码被类型化少一点-我简化了这个模板函数,一开始它检查类型是否兼容,但是泛型被过度使用了(在c#land中也是如此)但我刚才说这将是15-20个不同的类型,所以15-20个函数。我可能会使用重载,但Hipoteltic有办法使用模板-现在我只是curious@Sawyer我已经更新了答案以显示您的所有选项。谢谢。我将使用您关于过载的建议;)别忘了添加删除刚刚更新的指针的功能。尽管使用
std::unique\u ptr
可以解决这个问题。谢谢您的观察:)
class A
{
public:

    template <typename T>
    std::vector<std::pair<std::string, T>>& getVector() {
        auto vectors = std::tie(V1, V2);
        return std::get<std::vector<std::pair<std::string, T>>&>(vectors);
    }

    template <class T>
    void addElement(T Obj) {
        getVector<T>().emplace_back(Obj.Name, Obj);
    }

    std::vector<std::pair<std::string, B>> V1;
    std::vector<std::pair<std::string, C>> V2;
};
template <typename ... Ts>
class A_Impl
{
private:
    template <typename T>
    decltype(auto) getVector() const {
        return std::get<std::vector<std::pair<std::string, T>>>(Vs);
    }
    template <typename T>
    decltype(auto) getVector() {
        return std::get<std::vector<std::pair<std::string, T>>>(Vs);
    }
public:

    template <class T>
    void addElement(T Obj) {
        getVector<T>().emplace_back(Obj.Name, Obj);
    }
private:
    std::tuple<std::vector<std::pair<std::string, Ts>>...> Vs;
};

using A = A_Impl<B, C>;
class A{
public:

  template < typename T >
  void addElement(T obj)
  {
    getVector<T>().push_back(std::make_pair(obj.Name,obj));
  }

  template < typename T >
  T& getElement(size_t index)
  {
    return getVector<T>().at(index).second;
  }

private:
  vector<std::pair<std::string, B>> V1;
  vector<std::pair<std::string, C>> V2;

  template < typename T >
  vector<std::pair<std::string, T>>& getVector();
};

template <>
vector<std::pair<std::string, B>>& A::getVector<B>() { return V1; }
template <>
vector<std::pair<std::string, C>>& A::getVector<C>() { return V2; }