模板类的唯一容器

时间:2018-09-05 13:03:55

标签: c++ templates

我有一个算法(此处未预先设置),该算法将不同的参数(int,float,vector)作为输入。 我的设计想法是要有一个容纳所有这些不同参数的容器。
要达到这个目的,我有一个基类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。 还有其他设计容器的方法吗?

非常感谢!

2 个答案:

答案 0 :(得分:1)

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

std::variant

正如评论所建议的,variant是一组预定义的数据类型的类型安全联合,您可以将其放入variant的模板参数中。 例如,std::variant<int,float,double>可以容纳intfloatdouble类型的任何值,但不能包含其他任何值。

要使用存储的值,可以将访问者模式与std::visit()函数一起使用。其他功能可以让您知道哪些预设类型存储在变量(index())中并从中提取值(使用get())。如果您尝试提取错误类型的值,则get()函数将引发异常

std::any

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

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

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

答案 1 :(得分:0)

多态性的替代方式是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可以提供帮助,但是您必须了解每种派生类型。