0

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

template <typename Iterator1,
          typename Iterator2> double operator()( Iterator1 it1,
                                                 Iterator2 it2 ) const
{
  return( 0.0 );
}

我现在有一组可以用不同的仿函数创建的对象。我通过模板创建者函数解决了这个问题:

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 );

在评论中,还建议使用虚函数。但是,如上所述的当前仿函数设计不适用于虚函数,因为编译器无法使函数模板为虚拟。调整仿函数类以将两个迭代器类型作为模板参数是可能的,但非常笨拙。

编辑

仿函数的工作方式与 FLANN 中使用的类似。有关示例,请参见 git 存储库。我看不出如何以不同的方式指定这些函子。

4

1 回答 1

2

在考虑了您的要求之后,这是我想到的第一件事:您的不同仿函数显然不能像现在定义的那样从公共基类派生,因为您不能使模板化为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???

但是 AFAICS 你不需要知道外面函子的确切类型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");

简而言之:将工厂参数向下传递到您知道迭代器类型的点,即您必须参数化仿函数工厂的类型。调用您知道需要的每个输入的工厂,即类型和非类型参数。

于 2013-04-09T07:35:37.767 回答