我正在研究一个相当紧密耦合的库,到目前为止已明确假设所有计算都是用双精度完成的。我正在将一些核心类转换为模板,以便我们可以使用std::complex<double>
开始计算。到目前为止,我已经注意到我们的课程中有10个已经注意到模板扩散的趋势。当一个类变成模板时,使用模板化类的任何其他类似乎也需要模板化。我想我可以通过为我的模板定义抽象基类来避免这种扩散,这样其他类就可以使用指向抽象类的指针,然后引用派生的double
或std::complex<double>
版本类。这似乎在标题级别起作用,但是当我深入研究源文件时,模板化的类通常会具有计算类型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
的向量来填充第二个案例。这是否必须使调用类成为模板?有人可以推荐另一种策略来减少模板的扩散吗?
答案 0 :(得分:1)
我认为你假设第一个用例会起作用已经错了。如果您有一个抽象基类,那么value
是其成员,您可以通过std::shared_ptr<AbstractFunction>
或value
调用它不是它的成员,只有在您知道派生班&#39;类型。在第一种情况下,AbstractFunction::value
方法必须具有固定的返回类型,它不能依赖于Scalar
,这是派生类的模板参数。
那说:根据我的经验,这两个概念往往不能很好地融合。您要么想要使用完整界面创建抽象基类,要么想要模板。在后一种情况下,拥有抽象基类通常没有必要/没有好处。然后,使用您的模板的代码也可以使用模板。
可能对您有帮助的是&#34; export&#34;来自Function
的模板参数,即
template<typename T>
class Function
{
public:
using value_type = T;
value_type value() const;
// ...
};
在代码的其他部分,如果您不想直接写出(并限制自己)T
,请使用一个模板Function
,其行为类似于Function
1}}:
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);
}
请注意,这只是一个选项,我不知道它是否是您用例的最佳选择。