【问题标题】:unique container for template class模板类的唯一容器
【发布时间】:2018-09-05 13:03:54
【问题描述】:

我有一个算法(这里没有预设),它以不同的参数(int、float、vectors)作为输入。 我的设计理念是拥有一个包含所有这些不同参数的容器。
为了实现这一点,我有一个基类 Parameter 和一个派生的模板类 TypeParameter。 这些参数将保存在一个容器中。

设计如下:

    #pragma once

#include <utility>
#include <memory>
#include <string>
#include <vector>

namespace parameter
{
    /*
        Interface for parameter
    */
    class Parameter
    {
    public:
        Parameter() {}
        Parameter(std::string param_name) : name(param_name) {}
        Parameter(const Parameter&& other) noexcept : name(std::move(other.name)) {}
        virtual ~Parameter() {}

        inline const std::string get_name() { return name;  }

    private:
        std::string name;
    };

    /*

    */
    template<class T>
    class TypeParameter
        : public Parameter
    {
    public:
        TypeParameter(std::string param_name, T new_value) : Parameter(param_name), value(new_value) {}
        TypeParameter(const TypeParameter&& other) noexcept : Parameter(std::move(other)), value(std::move(other.T)) {}

        inline const T get_value() { return value; }

    private:
        T value;
    };

    /*
        Container for parameters
    */

    class ParameterSet
    {
    public:
        ParameterSet() {}

        void add(std::unique_ptr<Parameter> param) { data.push_back(std::move(param)); }

    private:
        std::vector <std::unique_ptr<Parameter>> data;
    };

} //namespace parameter

主要是:

    #include <iostream>
#include <string>

#include "Parameter.h"

using parameter::TypeParameter;
using parameter::Parameter;
using parameter::ParameterSet;

void foo(std::unique_ptr<Parameter> p)
{
    std::cout << p->get_value(); // ERROR
}

int main(int argc, char *argv[])
{
    TypeParameter<int> *iparam = new TypeParameter<int>("ee", 3);
    std::unique_ptr<Parameter> p = std::make_unique <TypeParameter<int>>("foo", 3);


    foo(std::move(p));

    ParameterSet param_set;
    param_set.add(std::unique_ptr<Parameter>(iparam));
    param_set.add(std::move(p));

    getchar();
}

我的问题是我无法在没有演员表的情况下获得价值。

因此,我的问题是如何将 unique_ptr 从 Parameter 类转换为派生的 TypeParameter。 是否有另一种设计容器的方法?

非常感谢!

【问题讨论】:

  • 听起来你想要一个 std::variant 的容器。
  • 如果你有一组有限的参数类型,你想用std::visit 处理std::variant 可能是你想要的方式。
  • 或者将虚拟方法添加到Parametervirtual void print() const = 0
  • 我不知道我可以用 virtual void print() 做什么。我需要获取参数的值。
  • @FrançoisAndrieux 或std::any。无论如何,演员是必要的

标签: c++ templates


【解决方案1】:

您不必重新发明轮子。您可以使用标准库中的几个类:

std::variant.

根据 cmets 的建议,variant 是一组预定义数据类型的类型安全联合,您将其放入 variant 的模板参数中。 例如,std::variant&lt;int,float,double&gt; 可以保存 intfloatdouble 类型的任何值,但不能保存其他值。

要使用存储的值,您可以使用带有std::visit() 函数的访问者模式。其他函数允许您知道哪些预设类型存储在变量 (index()) 中并从中提取值(使用 get())。如果尝试提取错误类型的值,get() 函数会抛出异常

std::any

是另一个可以保存不同数据类型的实用程序。与variant 不同,您不必在编译时知道类型。基本上,它将void* 存储到带有typeinfo 的数据中以记住其原始类型。然后,您可以使用any_cast 将变量转换回其原始类型。就像variant 一样,尝试转换为错误的类型时会引发异常。

这两个类在 C++ 17 中可用。如果您无法使用这些功能,它们也包含在 boost 中(分别为 boost:variantboost:any

您可以将一组值存储在标准库容器中,例如在std::vector&lt;std::variant&lt;int,float,double&gt;&gt;std::vector&lt;std::any&gt;&gt; 中。

【讨论】:

    【解决方案2】:

    std::variant/std::any 的替代方法是多态性:

    class Parameter
    {
    public:
        Parameter(const std::string& param_name) : name(param_name) {}
        virtual ~Parameter() = default;
    
        const std::string& get_name() const { return name;  }
    
        virtual void printValue() const = 0;
        // Other virtual methods
    
    private:
        std::string name;
    };
    
    template<class T>
    class TypeParameter : public Parameter
    {
    public:
        TypeParameter(const std::string& name, const T& t) : Parameter(name), value(t) {}
    
        // Non virtual method when we don't access it by base class.
        const T& get_value() const { return value; }
    
        void printValue() const { std::cout << value; }
    
    private:
        T value;
    };
    

    然后是你的

    void foo(const Parameter& p)
    {
        std::cout << p.get_value(); // ERROR
    }
    

    变成

    void foo(const Parameter& p)
    {
        p.print();
    }
    

    如果您不想在Parameter 中添加很多虚方法,那么Visitor pattern 可以提供帮助,但是您必须了解每个派生类型。

    【讨论】:

      猜你喜欢
      • 2013-05-11
      • 2021-07-29
      • 1970-01-01
      • 1970-01-01
      • 2016-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-21
      相关资源
      最近更新 更多