如何与函子一起使用工厂模式

How to use the factory pattern with functors?

本文关键字:工厂 模式 一起      更新时间:2023-10-16

我有一组函数用于计算对象范围上的特定内容。本质上,每个函子都实现了operator():

template <typename Iterator1,
          typename Iterator2> double operator()( Iterator1 it1,
                                                 Iterator2 it2 ) const
{
  return( 0.0 );
}
我现在有了一组对象,可以用不同的函子创建。我通过模板化creator函数解决了这个问题:
template <class Functor> Foo createFoo( ... // some parameters for foo objects
                                        Functor f = Functor() )
{
  // calculate stuff for "foo" using functor "f"
}

我现在想要委托函数选择给我的程序的用户,所以我决定创建一个函数工厂。给定一个函子的描述性名称,我想创建合适的函子,以便它可以用于创建所有Foo对象,如上面所示。

这就是我被卡住的地方:我不能创建一个返回模板化的函子的工厂,因为我不能在不编写我想要创建的函子的确切类型的情况下调用这个函数。

我考虑使operator()成为一些基类的虚函数,即FunctorBase,但我不希望与虚函数调用相关的性能开销。为了避免上述开销,我首先选择使用模板。

我在这里陷入僵局,非常感谢你的意见。

编辑:

我打算做什么(无效代码):

DistanceFunctor f = createFunctor( "Bar" ); // Create a functor from a client-supplied string
Foo createFoo( ..., // parameters for foo
               f );

在评论中,也建议使用虚函数。然而,如上所述的当前函子设计不适用于虚函数,因为编译器不能使函数模板虚。可以调整functor类,使其接受两个Iterator类型作为模板形参,但这非常笨拙。

编辑:

函子的工作原理与FLANN中使用的函子相似。请参阅git存储库以获取示例。

考虑了您的要求,这是我想到的第一件事:显然,不同的函子不能像现在这样从公共基类派生,因为不能将模板化的operator()设置为虚函数。但是,如果将模板形参从操作符推到函子本身,可以使该操作符虚:

template <class Iterator>
struct Functor {
  virtual double operator()(Iterator it1, Iterator it2) const = 0;
};

这有什么用?乍一看,将模板置于Functor级别并不好,因为现在必须知道createFunctor调用之外的形参,实际上,如果调用它,必须显式指定迭代器类型:

//some concrete functors
template <class It>
struct FuncImpl_Bar : Functor<It> { /* ... implement op()(It, It) ... */ }:
template <class It>
struct FuncImpl_Meow : Functor<It> { /* ... implement op()(It, It) ... */ }:
template <class Iterator>
std::shared_ptr<Functor<Iterator>> createFunctor(std::string const& str)
{
  if (str == "Bar") return std::make_shared<FuncImpl_Bar<Iterator>>(/* args *);
  else return return std::make_shared<FuncImpl_Meow<Iterator>>(/* args *);
}
//...
auto MyFunctor = createFunctor<???>("Bar"); //what iterator type???

但是你不需要知道createFoo之外的函子的确切类型-如果createFoo知道该类型就足够了:

Foo createFoo( ... // some parameters for foo objects
                                        std::string const& str ) //look mum, no templates!
{
  typedef whatever_the_container_i_use::iterator Iter;
  Functor<Iter> MyFunctor = createFunctor<Iter>(str);
  // calculate stuff for "foo" using functor "f"
}
//...
auto myFoo = createFoo(args, "Bar");
auto myOtherFoo = createFoo(args, "Moo");

简而言之:传递工厂形参到你知道Iterator类型的地方,也就是你必须用来参数化工厂函子的类型。调用工厂,在那里你知道所有需要的输入,即类型和非类型参数。