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