c++:有界数字的异构模板
c++: heterogeneous template for bounded numbers
我想创建一个列表(std::container或甚至列表*都可以)的数字(int和double),可以对它们施加限制。
template<typename T>
class setting {
public:
std::string name, units;
T value, min, max, step;
setting(std::string n, T val) : name(n), value(val) { }
setting operator++(int) {
setting tmp = *this;
value += step; if(value > max) value = max;
return tmp;
}
};
...
list.add(new setting<int>("channel", 4));
list.add(new setting<double>("amplitude", 5.6));
...
for(int i = 0; i < list.size(); i++)
std::cout << list[i].name << ": " << list[i].value << std::endl;
我尝试了几种不同的方法,但我对它们都不满意。不能从公共基类派生,因为基类类型不知道' value',因为它不知道类型,或者必须提前定义类型。用宏模板试过,但是downcast感觉很草率。有没有一种方法可以做到这一点,而不需要使用带有类型标识符的所有类型的联合来选择正确的成员?
到目前为止,带重载构造函数的boost::variant似乎满足了我的要求,除了必须在编译时枚举所有类型:
class setting {
public:
boost::variant<
bool,
int8_t,
uint8_t,
int16_t,
uint16_t,
int32_t,
uint32_t,
int64_t,
uint64_t,
float,
double,
std::string
> value;
std::string name;
setting(std::string n, int v) : name(n), value(v) { }
setting(std::string n, double v) : name(n), value(v) { }
setting(std::string n, std::string v) : name(n), value(v) { }
};
typedef std::map<std::string, setting*> MapType;
typedef MapType::const_iterator MapItr;
int main() {
MapType settinglist;
settinglist["height"] = new setting("height", 1.3);
settinglist["width"] = new setting("width", 5);
settinglist["name"] = new setting("name", "the name");
for(MapItr i = settinglist.begin(); i != settinglist.end(); ++i) {
std::cout << i->second->name
<< " : " << i->second->value
<< std::endl;
}
return 0;
};
给:
height : 1.3
name : the name
width : 5
可能是虚拟toString
和fromString
函数的公共基类?然后你的for循环变成:
list<setting_base> lst;
for( list<setting_base>::iterator it = lst.begin(); it != lst.end(); ++it )
std::cout << it->name << ": " << it->toString() << std::endl;
如何将普通类型包装在Boost.Operators中?
template <class T, T max = numeric_limits<T>::max(), T min = 0>
class Saturate
: boost::operators<Saturate<T, max, min>, T >
{
private:
T _value;
void normalize() {
if(_value < min) _value = min;
if(_value > max) _value = max;
}
void toNormal(T t) {
if(t < min) return min;
if(t > max) return max;
return t;
}
public:
Saturate(T t = T()) : _value(toNormal(t)) {}
T value() { return _value; }
Saturate& operator+=(const Saturate& x)
{ _value += x._value; normalize(); return *this; }
Saturate& operator-=(const Saturate& x)
{ _value -= x._value; normalize(); return *this; }
...
};
...
std::vector<Saturate<int, 1023, -1023> > volume;
...
volume[3] = 50000; // really loud
std::cout << volume[3].value(); // Not so loud
我认为你要么把所有东西都塞进一个类型(意思是忘记整型,只使用double),要么定义一个更通用的基类型。
您注意到的泛型基类型的问题是,它是泛型的。您将丢失类型信息,这些信息在以后访问容器中的元素时无法恢复。
我认为你的设计目标不一致。您应该创建一个足以满足您需求的通用接口(这是类型无关的),或者选择一种类型并坚持使用它。
我将首先说您可以在基类中提供一些toInt
和toDouble
和toInt64
方法。然后,如果你需要双精度值,你只需要请求它。它只需要每个人付出最少的努力。
如果做不到这一点,您可以用virtual void value(Operator&) const
方法替换常规的virtual int value() const
方法。Operator
将提供自己的虚函数,每个虚函数都接受您想要操作的一种类型。本质:
struct Operator {
virtual act(int) = 0;
virtual act(double) = 0;
//repeat for other types
};
struct Base {
virtual value(Operator&) const = 0;
};
在基类型上调用value
时,虚拟调度将确保调用正确的实现。在该实现中,您为act
提供了适当的静态类型,并且重载解析开始生效。您可以在Operator
实例中实际执行计算,或者只是存储结果并提供一个访问器。在前一种情况下,您可以为每种类型做一些独特的事情,比如使用一种算法,它可以更快地处理整数类型,但没有精度。在后一种情况下,您可以更进一步,在Base
struct Base {
//other stuff
template<typename Operator>
typename Operator::ResultType value() const {
Operator op;
value(op);
return op.result();
}
}
// later
cout << basePtr->get<IntGetter>();
当然,这样做的最终结果是用一种极其复杂的方式来做我最初建议的事情。
///////我刚注意到你对原来问题的修改。有这么多可能的基本类型,这变得不太可行。您必须在Operator类中提供每个基本类型的重载。你可以为基类Operator提供默认实现;比如对所有整型调用act(int)
,对所有浮点型调用act(double)
,那么每个实现只需要两个重载,再加上特定用例所需的任何额外重载。
但是现在我正在寻找YAGNI。你有一个复杂的基类,只是这样你可以提供设置,节省几个字节不存储完整的int
?你真的可以不把所有东西都存储为double
吗?它精确地存储了一堆整数值。或者使用boost::variant
,并将自己限制为int型、双精度型和字符串。
- 在C++中,如何创建包含可变模板对象的异构向量?
- 创建异构顶点数据数组的可移植方法
- std::variant vs指向C++中异构容器基类的指针
- C++中的集合(异构类型的数组)
- 从异构列表中提取数据
- Push_back一组(异构)向量的实现
- 使用 std::vector<char> 作为异构记录的存储是否安全?
- 是否可以使用 std::vector<std::any> vec;这将导致异构数据类型
- 异构容器查找 C++98
- 编译时排序的异构元组
- 异构初始化列表
- 派生实例不是指针时的基类的异构容器
- 顺序异构函数执行器
- 我们可以使用异构查找比较器对 STL 关联容器执行"partial-match"搜索吗?
- 异构作业处理器的并行化
- 如何解析没有前置标记的异构列表
- C++异构类型迭代器的迭代器
- 异构变量非类型模板参数计数是否灵活
- 如何在异构类的实例上循环调用具有相同名称和参数的方法
- c++:有界数字的异构模板