如何重构具有相同行的函数,唯一不同的是一个函数调用?

how to refactor functions that have same lines with only difference being one function call?

考虑以下代码片段

template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
    size_t prev_count = Count();
    if(count < prev_count)
    {
       DestroyMemory(prev_count, count);
    }
    else if(count > prev_count)
    {
      Reserve(count);

      for(size_t i=prev_count; i<count; i++)
      {
         // change in function call
         m_block.DefaultConstruct();
      }
    }
  }

这里是相同函数的重载

  template<typename T>
  void MyDynamicArray<T>::resize(const T &object, size_t count)
  {
     size_t prev_count = Count();
    if(count < prev_count)
    {
       DestroyMemory(prev_count, count);
    }
    else if(count > prev_count)
    {
      Reserve(count);

      for(size_t i=prev_count; i<count; i++)
      {
         // change in function call
         m_block.CopyConstruct(object);
      }
    }
  }

我认为重构调整大小函数的一种方法是提供 const T *pObject 作为默认参数。并检查是否提供,然后调用 CopyConstruct.

可以提供另一种方法,使一个调整大小成为一种调用另一个调整大小的包装器。

最好的方法是什么?

没有"the best approach"这样的东西可以普遍适用于所有可能的情况。例如,如果代码膨胀不是一个问题,你可以有一对公共函数的外观,将适当的 lambda 传递给公共函数:

template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
    resize_common(count, [] { m_block.DefaultConstruct(); });
}

template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
    resize_common(count, [&] { m_block.CopyConstruct(object); });
}

template <typename T, typename lambda_t>
void MyDynamicArray<T>::resize_common(size_t count, lambda_t &&lambda)
{
    size_t prev_count = Count();
    if(count < prev_count)
    {
       DestroyMemory(prev_count, count);
    }
    else if(count > prev_count)
    {
      Reserve(count);

      for(size_t i=prev_count; i<count; i++)
      {
         lambda();
      }
    }
}

如果代码膨胀是一个问题,那么您自己提供的一种可能性的变体:

template <typename T>
void MyDynamicArray<T>::resize(size_t count)
{
    resize_common(count, null);
}

template <typename T>
void MyDynamicArray<T>::resize(const T &object, size_t count)
{
    resize_common(count, &object);
}

template <typename T>
void MyDynamicArray<T>::resize_common(size_t count, const T *object)
{
    size_t prev_count = Count();
    if(count < prev_count)
    {
       DestroyMemory(prev_count, count);
    }
    else if(count > prev_count)
    {
      Reserve(count);

      for(size_t i=prev_count; i<count; i++)
      {
         if (object)
              m_block.CopyConstruct(*object);
         else
              m_block.DefaultConstruct();
      }
    }
}

我相信人们可以想到相同的一些变体。最重要的是,要回答 "which one is the best",必须考虑您的个人需求,考虑每个替代实现满足需求的程度,然后选择其中之一。代码膨胀应该最小化吗?整体性能有问题吗?等...

一个解决方案是创建一个虚拟对象,您可以将其传递给新函数 m_block.Construct() 以表明它是默认构造:

struct default_construct_t { };

我们像这样使用:

template <typename T>
void MyDynamicArray<T>::resize(size_t count) {
    resize(count, default_construct_t());
}

template <typename T, typename Obj>
void MyDynamicArray<T>::resize(size_t count, Obj const& obj)
{
    size_t prev_count = Count();
    if(count < prev_count)
    {
       DestroyMemory(prev_count, count);
    }
    else if(count > prev_count)
    {
      Reserve(count);

      for(size_t i=prev_count; i<count; i++)
      {
         // change in function call
         m_block.Construct(obj);
      }
    }
  }

现在您只需为 Construct(default_construct_t )Construct(T const& ) 提供重载。