我正在开发一个相当紧密耦合的库,到目前为止,它已经明确假设所有计算都是用 double 完成的。我正在将一些核心类转换为模板,以便我们可以开始计算 std::complex<double>
.到目前为止,我已经对大约 10 个类(class)进行了模板化,并注意到模板激增的趋势。当一个类被模板化时,任何其他使用模板化类的类似乎也需要模板化。我想我可以通过为我的模板定义抽象基类来避免这种扩散,这样其他类就可以使用指向抽象类的指针,然后引用 double
。或 std::complex<double>
派生类的版本。这似乎在 header 级别起作用,但是当我深入研究源文件时,模板化类通常会具有计算 double
类型的值或值容器的函数。或 std::complex<double>
.仅仅因为源文件中的几行由于其他一些类的返回类型而不同,就对整个类进行模板化似乎是一种浪费。
auto
的使用似乎是解决此问题的一种可能方法,但我不能 100% 确定它会起作用。假设我有一个抽象基类 AbstractFunction
从中Function<Scalar>
派生,其中 Scalar
可以是double
或 std::complex<double>
.现在假设我们有两个成员函数:
virtual Scalar Function<Scalar>::value(double x);
virtual void Function<Scalar>::values(std::vector<Scalar> &values, std::vector<double> x);
并且假设我有一些其他类(我不想模板化)具有调用其中一个的成员函数。
// populate double x and std::vector<double> xs
auto value = functionPtr->value(x);
std::vector<auto> values;
functionPtr->values(values, xs);
// do something with value and values
哪里functionPtr
类型为 std::shared_ptr<AbstractFunction>
.
我可以看到 auto
为第一种情况工作,但我不相信我可以构建 auto
的 vector 被第二个填满。这是否需要使调用类成为模板?有人可以推荐另一种策略来减少模板的扩散吗?
最佳答案
我认为您假设第一个用例会起作用已经是错误的。如果你有一个抽象基类,那么 value
是它的成员,你可以通过std::shared_ptr<AbstractFunction>
调用它或 value
不是它的成员,只有当您知道派生类的类型时才可用。在第一种情况下,AbstractFunction::value
方法必须有一个固定的返回类型,它不能依赖于Scalar
, 是派生类的模板参数。
也就是说:根据我的经验,这两个概念通常不能很好地混合。您要么想要创建一个具有完整接口(interface)的抽象基类,要么想要一个模板。在后一种情况下,拥有抽象基类通常没有必要/也没有好处。然后,使用您的模板的代码也适用于模板。
可能对您有帮助的是从 Function
中“导出”模板参数,即
template<typename T>
class Function
{
public:
using value_type = T;
value_type value() const;
// ...
};
在代码的其他部分,使用采用任何 T
的模板。表现得像Function
如果你不想直接写出(并限制自己)到 Function
:
template<typename T>
void something( const std::shared_ptr<T>& functionPtr )
{
// ignoring where x comes from...
using V = typename T::value_type;
V value = functionPtr->value(x);
std::vector<V> values;
functionPtr->values(values, xs);
}
请注意,这只是一个选项,我不知道它是否是您用例的最佳选择。
关于c++ - 避免模板扩散,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29853609/