我有一个算法(此处未预先设置),该算法将不同的参数(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。 还有其他设计容器的方法吗?
非常感谢!
答案 0 :(得分:1)
您不必重新发明轮子。您可以从标准库中使用几个类:
std::variant
。正如评论所建议的,variant
是一组预定义的数据类型的类型安全联合,您可以将其放入variant
的模板参数中。
例如,std::variant<int,float,double>
可以容纳int
,float
或double
类型的任何值,但不能包含其他任何值。
要使用存储的值,可以将访问者模式与std::visit()
函数一起使用。其他功能可以让您知道哪些预设类型存储在变量(index()
)中并从中提取值(使用get()
)。如果您尝试提取错误类型的值,则get()
函数将引发异常
std::any
是另一个可以保存不同数据类型的实用程序。与variant
相对,您不必在编译时就知道类型。基本上,它使用void*
将typeinfo
存储到数据中以记住其原始类型。然后,您可以使用any_cast
将变量强制转换回其原始类型。就像variant
一样,在尝试强制转换为错误类型时会引发异常。
这两个类在C ++ 17中可用。如果您无法使用这些功能,它们也将包含在boost中(分别为boost:variant
和boost: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可以提供帮助,但是您必须了解每种派生类型。