【问题标题】:Using enum members to templatise member functions使用枚举成员模板化成员函数
【发布时间】:2014-07-30 17:02:31
【问题描述】:

我正在编写一个可以在不同模式下实例化的类。一个简单的案例也许 一个平均计算机,可以根据模式计算不同类型的平均值。

该类将由其他一些代码实例化,并且该类代码将通过函数指针通用。必须根据模式定义与不同模式关联的特定功能并设置指针。

我的样子是这样的

    enum StatMode { EMA, SMA} ;

    class MeanComputer {
    public:
        MeanComputer ();
        MeanComputer (const MeanComputer& orig);
        virtual ~MeanComputer();
        template <StatMode> double Update (double x);
        template <StatMode> double Sample (double x);
        void Reset();
        void setFunction() { 
            if (mode == EMA ) do_calc = /*EMA mode function*/ ;
        }  
        double (MeanComputer::*do_calc)(double);

    private:
        std::vector <double> window ;
        double mean ;
        double variance ;
        StatMode mode;
    };

    template <StatMode SMA> double MeanComputer::Update(double x) {
    }


    template <StatMode EMA> double MeanComputer::Update(double x) {
    }

但是这似乎没有编译并给出错误 错误:没有匹配函数调用 'MeanComputer::Update(double&)'

我该如何进行这项工作。 我理解一种方法是让每个这样的模式函数由不同的名称定义,并设置 然后是函数指针。虽然这似乎需要太多的命名,并且具有更简洁的模式模板功能似乎更优雅且更易于理解。

更新: 计算的方法不是在编译时设置的,而是在运行时设置的。但是,对于类的给定对象,模式保持不变,因此相应地设置指针将一劳永逸。 虚拟基类也可以,但在实际情况下,很多计算都是通用的, 并且只有一些特定或小的功能取决于模式。一个人为的例子可能是平均计算机更新某种坐标对象,它采用一对模式类型,SMA/EMA 和纬度/经度。因此,一个实例可能是经度平均值,而另一个实例是纬度平均值。完整的计算是相同的,只是一个读取不同的成员。

【问题讨论】:

  • 为什么不将枚举作为函数参数传递呢?为什么计算均值的方法需要在编译时设置?
  • @NeilKirk 因为它可以在编译时解决,而且switch语句很难看。
  • 好吧,我想我用错了术语。计算的方法不是在编译时设置的,而是在运行时设置的。但是对于类的给定对象,模式保持不变。但是使用 switch 效率低下,而且肯定更容易出错。均值只是一个例子,还有更复杂的场景。意思似乎只是一个简单的案例
  • 这既不优雅也不易于理解。这似乎正是实现基类和派生类以及确定要实例化哪个工厂的正确位置。
  • @Aggieboy 你对前者有多肯定,后者是意见。

标签: c++ templates enums function-pointers


【解决方案1】:
template <StatMode SMA> double MeanComputer::Update(double x) {
}

语法错误

template <> double MeanComputer::Update<SMA>(double x) {
  return 7.0;
}

是你的专长。

这种技术很少是个好主意。

如果您希望在运行时确定计算方法,这完全是错误的方法,因为您需要使用编译时常量来确定调用哪个Update

您可以使用具有template 类实现的纯虚拟基类来消除工厂函数之外的switch 的需要。

【讨论】:

  • 虚拟是大多数解决方案的最佳方式,因为大多数解决方案可能无法在编译时解决,但我认为函数的编译时解析没有任何问题,假设它的用法是已知的.当它是一个有效的方法时,为什么它“很少是一个好主意”。
  • @Aggieboy 因为编译时解析的重点是速度,但通常代码更复杂且灵活性较差,并且在实践中无论如何都没有速度增益。
  • @aggieboy 因为现在我们有一个函数Update,它被编写了两次(一次用于SMA,一次用于EMA)。没有共享代码,因此他们几乎没有理由成为template 彼此的表亲。使用此技术的唯一充分理由是,您在该参数上有 templated 的外部包装代码,该参数使用此方法作为一个细节的一部分:即使那样,您最好将方法编写为完全正常的方法,并具有执行重定向的存根方法/特征类。
  • @Yakk 你能详细说明重定向的存根特征吗?正如我已将问题编辑为 elabortae 一样,在大多数情况下,通用计算是相似的,只有少数情况会因模式而异。因此,为每个对象设置一个新类似乎有点过头了(而且更容易出错……如果计算中有一些错误)。看看我上面描述的纬度/经度方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多