c++ - 如何在容器中存储不同类型的模板化对象?

标签 c++ templates

假设我有一个 vector (或列表或任何可能更适合这里的容器),我想存储模板类型的多个对象(或指针)在:

std::vector<MyClass<double>> v;
// std::vector<MyClass<double> *> v;

不幸的是,我想在这个容器中存储不同的模板化对象(并且我需要在理想情况下以恒定的时间访问它们)。

我的第一直觉是围绕 MyClass 创建某种 WrapperClass ,它将在内部将任何 MyClass 作为成员变量进行管理,但事实并非如此我清楚如何将适当的类型传递给 MyClass:

#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>

using namespace std;

template<typename T>
class MyClass
{
public:
    MyClass() {}
    ~MyClass() {}
};

// templating this of course works, but it doesn't solve my problem
template<typename T>
class WrapperClass
{
public:
    WrapperClass()
    {
        m_object = MyClass<T>();
    }

    ~WrapperClass() { }

private:
    MyClass<T> m_object;
};

int main()
{
    WrapperClass<bool> tmp = WrapperClass<bool>();

    std::vector<WrapperClass<bool> *> v;

    return 0;
}

那么,是否有(A)vector不同的容器可以用于解决这个问题,或者(B)有一种方法可以解决这个问题?在构造函数内的WrapperClass中选择MyClass的类型?我在想一些类似的事情:

class WrapperClass2
{
public:
    WrapperClass2(unsigned int typeId)
    {
        switch (typeId)
        {
            case 0: m_object = new MyClass<bool>();
            case 1: m_object = new MyClass<int>();
            case 2: m_object = new MyClass<float>();
            default: m_object = new MyClass<double>();
        }
    }

    ~WrapperClass2()
    {
        delete m_object;
    }

private:
    MyClass * m_object;
};

另一个想法可能是拥有一些我将在 vector 中使用的父AbstractType,但我不确定这将如何帮助解决模板化类型问题。

最佳答案

类模板的不同实例化是完全不相关的类型,因此您不能拥有直接存储它们的容器。

您有几个选择:

  1. 保留指向类模板继承自的某个基类的指针集合:
class Base
{
    virtual ~Base {}
    virtual void someMethod() const = 0;
};
    
template <typename T>
class MyClass : public Base
{
    void someMethod() const
    {
        // stuff
    }
};
    
int main()
{
    std::vector<std::unique_ptr<Base>> objs;
    objs.push_back(std::make_unique<MyClass<int>>());
    objs.push_back(std::make_unique<MyClass<std::string>>());

    for (auto& i : objs) {
        i->someMethod();
    }
}

这是一种相当简单的方法,但它会因动态分配和 RTTI 而产生一些运行时开销。另请注意 someMethod无法返回T ,因为它是父类上的一个方法,不知道什么 T是。

  • 使用某种类型删除的包装器,例如 boost::any (或 C++17 中即将推出的 std::any)。
  • #include <any>
    #include <string>
    #include <vector>
    
    template <typename T>
    class MyClass {
     public:
      T someMethod() const {
        // stuff
        return {};
      }
    };
    
    void someFunctionThatTakesInt(int i) {}
    void someFunctionThatTakesString(std::string s) {}
    
    int main() {
      std::vector<std::any> objs;
      objs.push_back(MyClass<int>());
      objs.push_back(MyClass<std::string>());
    
      for (const auto& i : objs) {
        if (i.type() == typeid(MyClass<int>)) {
          auto& mc = std::any_cast<const MyClass<int>&>(i);
          someFunctionThatTakesInt(mc.someMethod());
        } else if (i.type() == typeid(MyClass<std::string>)) {
          auto& mc = std::any_cast<const MyClass<std::string>&>(i);
          someFunctionThatTakesString(mc.someMethod());
        }
      }
    }
    

    这种方法意味着您可以拥有 someMethod返回T ,但是使得处理从 vector 检索对象变得更加困难因为您必须先弄清楚它们是什么类型,然后才能对它们执行任何操作(您实际上是在滚动自己的 RTTI)。

  • 不要。
  • 重新思考一下为什么你首先需要这个。也许另一种方法可能效果更好。也许有回调或访客的东西。我不知道你的目标,所以我不能真正说出什么是合适的。

    关于c++ - 如何在容器中存储不同类型的模板化对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38601676/

    相关文章:

    image - 在 Meteor 中使用 Router 渲染模板后无法加载图像

    c++ - 如何创建可变参数模板函数来移动参数值并处理左值和右值?

    c++ - 添加 boost 库作为 Bazel 依赖项 c++

    C++ - Pthread 如何发送值

    c++ - 为什么不对指针强制执行 constness?

    iphone - 在 Xcode 中添加新模板

    templates - redux框架wordpress调用变量

    c++ - 如何将两个 cpp 添加到一个 cpp 程序文件

    c++ - 如何从字符串中复制每 16 个字节的数据?

    ruby-on-rails - 如何从 Controller 中包含的模块渲染js模板?