如何处理异质容器中的铸造

How to handle casting in Heterogenous container

本文关键字:何处理 处理      更新时间:2023-10-16

我正在尝试使用指向非模板基类的指针来实现异构容器。而派生类是一个模板。

注意:派生类类型在编译时是已知的。注意:容器尺寸是固定的。

第一次尝试:使用帮助程序数组来保存正确类型的整数表示形式。它的大小等于容器的大小。然而,我最终得到了许多if语句。

我的问题与此线程略有相似,但我不知道如何使用 std::type_index。

我试图避免使用Boost::variant运行时多态性来解决这个问题。

我的问题:有没有更好的方法来处理从基类到派生类的转换?

在我的实际问题中编辑1。 模板类有 16 种不同的类型。

例:

template<typename Color, typename Smell, typename Shape, typename Origin>
class Fruit{};

实现:

class Plant
{ public: std::string sound = "I am jst a plant";};
template <typename T>
class Fruit : public Plant
{public: std::string sound = "I am jst a Fruit!";};
// list of types known at compile time.
struct Apple{ };           // types = 0
struct Orange{ };          // types = 1
struct Banana{ };          // types = 2
template <>
class Fruit<Apple> : public Plant
{public: std::string sound = "I am Apple";};
template <>
class Fruit<Orange> : public Plant
{public: std::string sound = "I am Orange";};
template <>
class Fruit<Banana> : public Plant
{public: std::string sound = "I am Banana";};

template <typename T>
void MakeSound(T fruit)
{
std::cout << fruit->sound << std::endl;
}
int main() {
Plant* Basket[5] = {nullptr};
int types[5] = {0};
Basket[0] = new Fruit<Apple>;
types[0] = 0;
Basket[1] = new Fruit<Orange>;
types[1] = 1;
Basket[2] = new Fruit<Orange>;
types[2] = 1;
Basket[3] = new Fruit<Apple>;
types[3] = 0;
Basket[4] = new Fruit<Apple>;
types[4] = 0;

for (int i = 0; i < 5; ++i)
{
if (types[i] == 0)
{
MakeSound(static_cast<Fruit<Apple> *>(Basket[i]));
}
else if (types[i] == 1)
{
MakeSound(static_cast<Fruit<Orange> *>(Basket[i]));
}
else
{
MakeSound(static_cast<Fruit<Banana> *>(Basket[i]));
}
}
}

我建议使用虚函数来检测派生对象类型的 id;我建议在模板类参数中注册的类型 id(作为sound(以避免需要Fruit的专业化。

请:你标记了C++11;所以使用智能指针。

我的意思的一个例子

#include <string>
#include <vector>
#include <memory>
#include <iostream>
struct Plant
{ virtual std::size_t getTypeId () = 0; };
struct Apple
{ 
static constexpr size_t  typeId { 0U };
static std::string const & getSnd ()
{ static std::string sound { "I am Apple" }; return sound; }
}; 
struct Orange
{ 
static constexpr size_t  typeId { 1U };
static std::string const & getSnd ()
{ static std::string sound { "I am Orange" }; return sound; }
}; 
struct Banana
{ 
static constexpr size_t  typeId { 2U };
static std::string const & getSnd ()
{ static std::string sound { "I am Banana" }; return sound; }
}; 
template <typename T>
struct Fruit : public Plant
{
virtual std::size_t getTypeId () override { return T::typeId; }
static std::string const & getSnd () { return T::getSnd(); }
};

template <typename T>
void MakeSound(T fruit)
{ std::cout << fruit->getSnd() << std::endl; }
int main()
{
std::vector<std::unique_ptr<Plant>> bask;
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Orange>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Apple>);
bask.emplace_back(new Fruit<Banana>);
for ( auto const & up : bask)
{
switch ( up->getTypeId() )
{
case 0U:
MakeSound(static_cast<Fruit<Apple> *>(up.get()));
break;
case 1U:
MakeSound(static_cast<Fruit<Orange> *>(up.get()));
break;
case 2U:
MakeSound(static_cast<Fruit<Banana> *>(up.get()));
break;
default:
break;
}
}
}