如何编写可以处理对象或指针函数调用的模板函数?

时间:2013-08-05 17:18:58

标签: c++ templates

我希望能够编写一个模板函数,该函数可以调用容器的所有元素上的函数调用。我们可以假设函数名称始终相同。然而,未知的是容器是否保持物体或指针。即,我是否应该去引用。

template< typename TContainer >
void ProcessKeyedContainer( TContainer &keyedContainer )
{
  for ( auto it = keyedContainer.begin(); it != keyedContainer.end(); ++it )
  {
    // do some random stuff here.
    // ...

    auto value = it->second;
    value.Process(); // or value->Process() if the container has pointers
  }
}

...

std::map< int, CMyObject > containerOfObjects;
containerOfObjects[0] = CMyObject();

std::map< int, CMyObject* > containerOfPointers;
containerOfPointers[0] = new CMyObject();

// I would like both calls to look near identical
ProcessKeyedContainer( containerOfObjects ); 
ProcessKeyedContainer( containerOfPointers );

是否有一种简洁的方法可以在ProcessKeyedContainer中进行Process调用,而不会给调用者带来负担(即调用者不必知道以一种方式使用它来获取指针而另一种方式使用对象) ,而不必复制太多的代码?

1 个答案:

答案 0 :(得分:6)

重载的功能模板是救世主:

template<typename T>
void invoke(T * obj)  //when object is pointer
{
      obj->Process();
}

template<typename T>
void invoke(T & obj)  //when object is non-pointer
{
      obj.Process();
}

然后将其用作:

auto value = it->second;
invoke(value); //correct invoke() will be selected by the compiler!

但这还不够好,因为您可能希望在您编写的函数的其余部分中使用value执行其他操作。因此,如果您遵循上述方法,则会出现代码重复,因为invoke()将具有几乎相似的代码。

所以这是一个改进:不是使用invoke(),而是将指针转换为引用,以便您可以在函数中统一使用它。

template<typename T>
T& ensure_ref(T * obj)  //when object is pointer
{
      return *obj; //return the dereferenced object
}

template<typename T>
T& ensure_ref(T & obj)  //when object is non-pointer
{
      return obj; //simply return it
}

并将其用作:

auto & value = ensure_ref(it->second); //call ensure_ref to ensure reference!

value.Process(); //value is gauranteed to be NOT pointer!

//you might want to do this also!
value.xyz = abc; 

希望有所帮助!