我有一个很愚蠢的问题,但是我希望你能帮助我。
我有多个向量类,并且这些向量具有不同的存储类型。
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 :(
您有什么建议我该如何解决?我会非常感激的。
答案 0 :(得分:2)
而不是拥有
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);
}
答案 1 :(得分:1)
这可能是Tagged Tuple library的用例。这样就可以按关联的类型对容器进行索引。因此,处理数十个相似的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;
}
答案 2 :(得分:1)
您可以将“通用获取器”用作向量:
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>;
答案 3 :(得分:0)
如果您打算在一些地方使用向量,则可以专门设计一个模板来一次获得正确的向量,那么您的主模板代码可以是通用的:
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; }
答案 4 :(得分:-1)
如果您这样使用共享的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
}