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

时间:2017-07-19 08:09:40

标签: c++ c++11

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

注意:派生类类型在编译时是已知的。 注意:容器大小已修复。

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

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

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

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

在我的实际问题中

Edit1 。模板类有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]));
        }

    }
}

1 个答案:

答案 0 :(得分:1)

我建议使用虚函数来检测派生对象类型的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;
       }
    }
 }