逆变类型和扩展性
Contravariant types and extensibility
我正在编写一个用于优化的C++库,我遇到了一个奇怪的反变量类型的问题。
因此,我根据它们可以计算的信息来定义"函数"的层次结构。
class Function {
public:
double value()=0;
}
class DifferentiableFunction : public Function {
public:
const double* gradient()=0;
}
class TwiceDifferentiableFunction : public DifferentiableFunction {
public:
const double* hessian()=0;
}
这一切都很好,但现在我想为优化器定义接口。 例如,一些优化器需要梯度信息或 hessian 信息才能进行优化,而有些则不需要。 因此,优化器的类型与函数的类型是逆变的。
class HessianOptimizer {
public:
set_function(TwiceDifferentiableFunction* f)=0;
}
class GradientOptimizer : public HessianOptimizer {
public:
set_function(DifferentiableFunction* f)=0;
}
class Optimizer: public GradientOptimizer {
public:
set_function(TwiceDifferentiableFunction* f)=0;
}
我认为从类型论的角度来看这是有道理的,但奇怪的是,通常当人们想要扩展代码时,他们会继承已经存在的类。 例如,如果其他人正在使用这个库,并且他们想要创建一种需要比 hessian 更多信息的新型优化器,他们可能会创建一个类似
class ThriceDifferentiableFunction: public TwiceDifferentiableFunction }
public:
const double* thirdderivative()=0;
}
但是为了创建相应的优化器类,我们必须使HessianOptimizer扩展ThirdOrderOptimizer。 但是库用户必须修改库才能这样做! 因此,虽然我们可以添加 ThriceDifferentiableFunction 而无需修改库,但似乎逆变类型会丢失此属性。 这似乎只是类声明其父类型而不是其子类型这一事实的产物。
但是你应该如何处理这个问题呢?有什么办法可以做得好吗?
由于它们只是接口,因此您不必担心与它们的多重继承。为什么不让优化器类型成为兄弟姐妹而不是后代呢?
class OptimizerBase
{
// Common stuff goes here
};
class HessianOptimizer : virtual public OptimizerBase {
public:
virtual set_function(TwiceDifferentiableFunction* f)=0;
}
class GradientOptimizer : virtual public OptimizerBase {
public:
virtual set_function(DifferentiableFunction* f)=0;
}
class Optimizer : virtual public OptimizerBase {
public:
virtual set_function(TwiceDifferentiableFunction* f)=0;
}
// impl
class MyGradientOptimizer : virtual public GradientOptimizer, virtual public HessianOptimizer
{
// ...
};
相关文章:
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 如何使用于 catch2 测试和项目运行的 cmake 目标更具可扩展性和合理性?
- 逆变类型和扩展性
- TCP 服务器 w/ boost::asio,线程池与无堆栈协程的可扩展性
- 使用 Python 插件可扩展性编写跨平台应用程序的最简单方法
- C标准库的可扩展性对C++程序的影响有多大