如何使用模板根据类型将元素添加到各种容器中
How to add element to various container depending of type using template
我有一个相当愚蠢的问题,但我希望你能帮助我。
我有一个具有多个向量的类,这些向量具有不同的存储类型。
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;
}
在我的类 A 中,有一个模板函数可以向此向量添加元素:
template <class T> void addElement(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
我想出了这样的东西:
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);
}
但不幸的是,这段代码无法编译,因为以某种方式将模板编译为一个整体,如果我使用 B 作为模板参数,那么编译器无法将 B 转换为 C,尽管该程序永远不会达到这种转换可能发生的程度:(
您有什么建议如何解决此问题吗?我会非常伟大。
而不是有
template <class T> void addElement(T Obj);
只需重载函数即可。 那会给你
void addElement(const B& Obj)
{
V1.push_back({Obj.Name, Obj});
}
void addElement(const C& Obj)
{
V2.push_back({Obj.Name, Obj});
}
这为您节省了专用模板或需要 C++17 和if constexpr
在编译时做出决定的所有语法。
原因
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);
}
每个 if 块中的代码需要有效(即使永远无法访问(,但不能,因为您将在向量中添加不同类型的代码。if constexpr
有帮助,但我发现重载同样多,并且使代码不向后兼容。
这意味着您必须像
template <class T> void addElement(T Obj);
template <> void addElement(B Obj)
{
V1.push_back({Obj.Name, Obj});
}
template <> void addElement(C Obj)
{
V1.push_back({Obj.Name, Obj});
}
或使用if 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);
}
这可能是标记元组库的一个用例。它使按关联类型为容器编制索引成为可能。因此,处理数十个相似vector<std::pair<std::string, B>> 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;
}
你可以使用"generic 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;
};
更改成员资格可能有意义,直接使用std::tuple
。 您可能希望模板化整个类:
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; }
如果你像这样使用共享的 BaseClass 会怎样? 您必须为 BaseClass 创建一个通用接口,我不确定 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
}
相关文章:
- 有没有办法向这个向量添加元素?
- 如何在提升间进程中构建具有给定计数的向量并向其添加元素
- 如何在 Arduino 字符串的开头添加元素.类似于 JS unshift();
- C++向数组添加元素并调整数组大小
- 我无法向 c++ 添加元素
- BST 不添加元素
- 调整数组大小并添加元素 C++
- 向向量添加元素
- 如何在不使用标准算法的情况下在排序向量中添加 c 元素?
- 双链接列表添加元素不起作用,不知何故它总是保持为空
- 当我向 vector<int *> 添加元素时,我遇到了一些问题
- 动态地添加元素
- 静态2D数组,添加元素
- 在一个类中向向量添加元素不适用于其他类
- 在数组中添加元素将不接受类似的元素
- STD :: MAP-使用下标操作员与插入方法添加元素
- 动态数组添加元素而不创建结构变量/对象
- 以下向 c++ 向量添加元素的方法有什么区别
- 如何在 std::map 中添加元素自己进行分配
- C++在向量中添加元素的双精度