C++ 避免模板的扩散

C++ 避免模板的扩散,c++,templates,C++,Templates,我正在研究一个相当紧密耦合的库,到目前为止,它明确假设所有的计算都是用双精度完成的。我正在将一些核心类转换为模板,这样我们就可以开始使用std::complex进行计算。到目前为止,我已经制作了大约10个类的模板,并且注意到了模板激增的趋势。当一个类被模板化时,使用模板化类的任何其他类似乎也需要模板化。我想我可以通过为我的模板定义抽象基类来避免这种扩散,这样其他类就可以使用指向抽象类的指针,然后引用派生类的double或std::complex版本。这似乎在头级别起作用,但当我深入研究源文件时,

我正在研究一个相当紧密耦合的库,到目前为止,它明确假设所有的计算都是用双精度完成的。我正在将一些核心类转换为模板,这样我们就可以开始使用
std::complex
进行计算。到目前为止,我已经制作了大约10个类的模板,并且注意到了模板激增的趋势。当一个类被模板化时,使用模板化类的任何其他类似乎也需要模板化。我想我可以通过为我的模板定义抽象基类来避免这种扩散,这样其他类就可以使用指向抽象类的指针,然后引用派生类的
double
std::complex
版本。这似乎在头级别起作用,但当我深入研究源文件时,模板类通常会有一些函数,用于计算类型为
double
std::complex
的值或值容器。仅仅因为源文件中的几行由于某些其他类的返回类型不同而对整个类进行模板化似乎是一种浪费

使用
auto
似乎是解决这一问题的一种可能的方法,但我不能100%肯定它会起作用。假设我有一个抽象基类
AbstractFunction
,从中派生
Function
,其中
Scalar
可以是
double
std::complex
。现在假设我们有两个成员函数:

virtual Scalar Function<Scalar>::value(double x);
virtual void Function<Scalar>::values(std::vector<Scalar> &values, std::vector<double> x);
虚拟标量函数::值(双x);
虚空函数::值(std::向量和值,std::向量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
//填充双x和std::vector xs
自动值=功能PTR->值(x);
std::向量值;
函数PTR->值(值,xs);
//做一些有价值的事情
其中
functionPtr
属于
std::shared\u ptr
类型。
我可以看到
auto
适用于第一种情况,但我不相信我可以构造一个
auto
向量来填充第二种情况。这是否需要使调用类成为模板?有人能推荐另一种策略来减少模板的扩散吗?

我认为你已经错误地认为第一个用例会起作用。如果您有一个抽象基类,
value
是它的成员,您可以通过
std::shared_ptr
调用它,或者
value
不是它的成员,并且只有在您知道派生类的类型时才可用。在第一种情况下,
AbstractFunction::value
方法必须具有固定的返回类型,它不能依赖于派生类的模板参数
Scalar

这就是说:根据我的经验,这两个概念常常不能很好地结合。您要么想要创建一个具有完整接口的抽象基类,要么想要一个模板。在后一种情况下,拥有抽象基类通常没有必要/没有好处。然后,使用模板的代码也可以与模板一起工作

可以帮助您的是从
函数
中“导出”模板参数,即

template<typename T>
class Function
{
public:
    using value_type = T;
    value_type value() const;
    // ...
};

请注意,这只是一个选项,我不知道它是否是您用例的最佳选项。

在您的示例中,
AbstractFunction
也是模板吗?方法
value()
values()
AbstractFunction
中是否应该是纯虚拟的?您应该给出一个更详细的示例。AbstractFunction不是为函数和函数提供共同祖先的模板。我意识到我的示例可能有点缺陷,因为
value()
values()
函数依赖于模板参数,它们可能无法作为纯虚拟函数存在于
AbstractFunction
中。“这似乎有点浪费”--您的目标到底是什么?例如,“减少使用两个版本函数的程序的可执行文件的大小”实际上是否重要?听起来你只是为了避免模板而避免使用模板,而不是有一个实际的,具体的目标。我想我已经到了必须完全模板化一个类的地步,而这个类似乎并没有直接参与到我们支持
std::complex
的目标中,仅仅因为它有一个对已经模板化的类的引用。我不知道这是否有什么问题,只是觉得必须有更好的办法。我想你是对的。当我把这个抽象的基类概念进一步深入兔子洞时,它似乎越来越不像是一个可行的解决方案。似乎在我完成的时候,我们图书馆里的每一个类都将被模板化。
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);
}