函数的Iterator-reducer模式可能会也可能不会返回值

时间:2016-04-29 13:07:31

标签: c++ c++11

以下函数在每个元素上应用仿函数并减少返回值:

template <class FCT, class RED>
RED::TYPE forAllElements(FCT functor, RED reducer){
  for(/* all elem in elements */){
    reducer(functor(elem));
  }
  return reducer.value;
}

现在,有时我可能只想在所有元素上调用functor,而不是减少任何内容。基本上,我希望有类似的东西:

class FunctorThatReturnsNothing{
  void operator() (Elem e){
    // do something, return nothing...
  }
}

class DummyReducer{
  using TYPE = void; // ??? something like that ???

  template <class FCT>
  void operator() (/* ??? what here */){
    // do nothing...
  }
}

forAllElements(FunctorThatReturnsNothing(), DummyReducer());

但是由于我有reducer(functor(elem)),因此我不会编译,其中将void函数的不存在的返回值作为参数。

有没有办法让它适用于无效仿函数,而不会为void和非void情况重复forAllElements?

(对于怀疑XY问题的人:我基本上知道不同的迭代和减少方法,我认为所提出的回调方法适合我的情况。我只是想知道如何避免重复代码为&# 34;返回值+减少&#34;以及&#34;只是回调&#34;情况。)

3 个答案:

答案 0 :(得分:1)

我认为您可以制作VoidReducer课程,但不需要return reducer.value;,而是需要return reducer.getvalue();。然后你只需制作void VoidReducer::getvalue(){}

我还没有对此进行过测试,但这个想法应该可行。如果return f();和当前函数都返回f类型,则允许void

修改
现在我更仔细地阅读了这个问题,我发现你问的问题是reducer(functor(elem));行。
为此,我将根据decltype(functor(elem))进行编译时调度。

template <class Functor, class Reducer, class Elem>
void Combine(Functor functor, Reducer & reducer, Elem elem, std::true_type)
{
  functor(elem);
}

template <class Functor, class Reducer, class Elem>
void Combine(Functor functor, Reducer & reducer, Elem elem, std::false_type)
{
    reducer(functor(elem));
}

template <class Functor, class Reducer, class Elem>
void Combine(Functor functor, Reducer & reducer, Elem elem)
{
    Combine(functor, reducer, elem, std::is_same<decltype(functor(elem)), void>());
}

然后调用Combine代替reducer(functor(elem))会正确地减少functor的返回值,当且仅当它不是无效时。

PS:为参考品添加参考和std::forward电话。

答案 1 :(得分:1)

如果您仍然希望使用forAllElements函数而不是直接使用std::for_each,则可以创建不带减速器的函数重载,并在内部使用std::for_each

template <class FCT>
void forAllElements(FCT functor){
    std::for_each(std::begin(...), std::end(...), functor);
}

...

forAllElements(FunctorThatReturnsNothing());

如果无法为容器获取“迭代器”(如果使用非标准容器或指针),您当然可以拥有自己的循环,只需调用functor

答案 2 :(得分:0)

一种干净而灵活的方法是返回函数对象本身,而不是硬编码的value字段。

template <class FCT, class RED>
RED forAllElements(FCT functor, RED reducer){
  for(/* all elem in elements */){
    reducer(functor(elem));
  }
  return reducer;
}

然后,该操作可以没有返回值,甚至多个返回值,具有信息名称。

您可以将原始方法视为此原始组件的便捷包装:

template <class FCT, class RED>
RED::TYPE forAllElements_convenience(FCT functor, RED reducer){
  return forAllElements(functor, reducer).value;
}