一次只需要一个指向不同类型的指针的最佳方法是什么?

问题描述

我处于一种需要将指向未知类型对象的指针作为另一个类的成员的情况。 但是有效对象类型的列表在编译时是已知的。

说我有

// A class templated on T
template<class T> class obj;

// Now assume there are some objects of types obj<...> somewhere else
obj<int> obj1;
obj<double> obj2;

// Now,manager needs to create a pointer for these objects
// in a specific manner at construction-time

// Say,we have to choose a canonical object (and set the other as secondary)

// manager shouldn't be templated on T because It needs
// to have multiple members of type obj<...>
template<class R>
class manager
{
    shared_ptr<...> canObjPtr;
    shared_ptr<...> secObjPtr;
 public:   
    // once set,canonical obj is not expected to change
    explicit manager(string canonicalObj);
}

我该如何实现?

一些最初的想法并没有真正起作用:

  1. 我能想到的最有前途的方法是将T1和T2模板参数添加到管理器并按如下方式构造:manager<R,obj<int>,obj<double>>()。我觉得我应该在构造管理器之前使用静态函数抓取“ canonicalObj”字符串,然后决定由哪个管理器创建manager<R,obj<double>>manager<R,obj<double>,obj<int>>

  2. 如何直接在obj1 and obj2对象上“模板化”管理器。看起来可行吗?请注意,我可以向管理器中添加模板参数,因为它与某些运行时选择机制有关,该机制不喜欢使用多参数模板。

  3. 创建2个成员指针,而不是2个成员指针(请参阅下文,但这太糟糕了,肯定会使我为之疯狂:在使用任何一个指针之前,必须始终检查一个指针是否为空)

template<class R> manager
{
    sharedPtr<obj<int>> canObjPtrI;
    sharedPtr<obj<float>> canObjPtrF;

    // same for secObjPtr above
 public:
    explicit manager(string canonicalObj);
}
  1. std::any and std::variant(及其升压等效项)是不可能的,因为我想继续使用c ++ 11并且不能按策略使用升压。如果我违反其中一项规则,我会考虑升级到c ++ 17。

  2. 例如,我认为使用shared_ptr<void>不会带来任何好处,因为无论如何我都必须将指针强制转换为正确的类型,并且不能使用空指针。

  3. 对于union也可以这样说。与3相比几乎没有改善。

此外,如果您将其视为潜在的设计问题,请不要退缩。我邀请您指出您发现的任何缺陷/改进。

[编辑] 此代码试图执行的操作是...

基本上,如上所述,我需要从预先构造的obj<int> and obj<double>对象列表中选择一个规范的和辅助对象:

基于用户输入,类应决定一个规范对象,并根据此决定执行计算。我已经具有通过其名称(字符串)来引用这些对象的工具。唯一的问题是它们的类型不同,并且使它们从基类继承会限制我仅使用该基类的接口(对吗?)。

评论中要求的最小示例

// A base template for objects defines common
// and possibly different interface.
template<class T> class objBase
{
protected:
    field<T> f_;

public:

    // Public data type
    using fieldType = field<T>;

    // New selects from "Registered childs of objBase"
    // at runtime
    static shared_ptr<objBase>::New() const;

    // Pure virtual to update the obj
    virtual void update() = 0;

    // Const-Access to field
    const field<T>& getField() const;
};

// Created objects are also registered automatically to a database
// i.e. I can get (const-)refs to them by querying the database
shared_ptr<objBase<int>> obj1 = objBase<int>::New();
shared_ptr<objBase<int>> obj2 = objBase<int>::New();
shared_ptr<objBase<float>> obj3 = objBase<float>::New();

// In manager,something like this needs to happen
template<class R>
class manager
{
private:
    // Read 2 target obj names from user input
    pair<string,string> objNames;

    // Possible types for requested objs:
    // obj_a,obj_b : both objBase<int> or both objBase<float>
    // or they can have different types 
    // But we essentially need only:
    pointer<...> canonicalObj;
    pointer<...> secondaryObj;

    // These should be used like this
    void useObjField() const
    {
        // Not using auto for clarity
        const decltype(*canonicalObj)::FieldType& objField
            = canonicalObj->getField();
        for(int i=0; i < objField.size(); ++i)
        {
            // Loop through elements and use them for some calculations
            // Related to other fields in manager
        }
    }
};

解决方法

std::anystd::variant(以及它们的boost等效项)是不可能的,因为我想继续使用c ++ 11并且不能按策略使用boost。

仍然没有问题:您可以使用mpark::variant-它与C ++ 11兼容。还有其他这样的变体类实现。如果您想使用类似any的课程(不建议使用),请尝试使用linb::any-同样的想法;与C ++ 11兼容。

IIANM,这两个都是仅标头的库(忽略测试/示例程序),因此您甚至不需要任何复杂的安装;您可以获取标题的最新版本,或者对其进行超级组织,使用CMake正确构建和安装它们,然后使用CMake find_package()命令定位它们。

最后,“限定联合”将是使用变体的粗略选择。变体本质上是一个并集和一个变量,该变量告诉您​​并集中的哪些类型是活动的。为了简化使用和安全性,我不建议您这样做-但这可能意味着更少的代码。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...