Question Details

No question body available.

Tags

c++ coding-style coding-standards templates reusability

Answers (4)

Accepted Answer Available
Accepted Answer
April 8, 2025 Score: 4 Rep: 79,402 Quality: Expert Completeness: 50%

It is impossible for us to tell if there is a better way for merging such two similar but not identical functions without knowing the details of the actual functions and how the differences cam about.

What I can tell is how I would go about such a task.

First, I look at the differences and try to resolve them by seeing if a change made to function A, like the addition of debug information, could also be valuable where function B is used. Or by removing debug information that turns out to no longer being needed.

If there are any remaining differences, I check how often and in what way the calling code would be affected if I

  • add it to the function that doesn't have it
  • move it out of the function into the caller
  • add a flag (preferably as a non-type template parameter) to conditionally invoke behavior A or B

If either of those has an acceptably low impact, I take that route.

If there is no acceptable way to resolve the differences, I will likely keep the status quo (separate functions).

What I do not consider are unknown future requirements that may or may not pop up. Trying to anticipate the unknown future either leads to an overly complicated design that you will most likely not need, or to analysis paralysis (you get stuck in analyzing the options and never make any progress).

April 9, 2025 Score: 2 Rep: 15,844 Quality: Medium Completeness: 80%

In my experience, the easiest way to have a template that does specific things for one particular type is overloading.

void PrintDebugInfo(std::list& obj1, std::list& obj2) {
  // print debug info
}
template
void PrintDebugInfo(T&, T&) {} // fallback does nothing

template int FindMaxDistance(T& obj1, T& obj2, bool addDebugInfo) { // common code if (DEBUGENABLED) PrintDebugInfo(obj1, obj2); }

This is easy to extend to more types: just add more overloads to PrintDebugInfo. Sometimes you have to be a bit careful to avoid the fallback version being a better match than the specialized one.

That said, an alternative is to have special cases for some types in the function itself using if constexpr.

template 
int FindMaxDistance(T& obj1, T& obj2, bool addDebugInfo) {
  // common code
  if (DEBUGENABLED) {
    if constexpr (std::issamev) {
      // print debug info for list
    }
  }
}

Two more notes:

  • The identifier DEBUG_ENABLED starts with an underscore and an uppercase letter. Such identifiers are reserved for the implementation in all contexts, you are not allowed to define them in your own program!
  • The Container concept is left as an exercise to the reader.
April 12, 2025 Score: 2 Rep: 4,971 Quality: Low Completeness: 40%

Sure, combine to reuse by splitting them:

result = FindMaxDistanceList(obj1, obj2);
if (DEBUGENABLED_) 
   PrintDebugInfo(obj1, ob2);

This way, each call site gets to decide what to print, and business logic has less logging code sprinkled around.

April 8, 2025 Score: 0 Rep: 11 Quality: Low Completeness: 60%

In your case, both FindMaxDistanceVector and FindMaxDistanceList perform analogous operations on std::vector and std::list, respectively.

By using iterators, your function can operate on any container type that supports iteration

template

int FindMaxDistance(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, bool addDebugInfo) { if (std::distance(first1, last1) != std::distance(first2, last2)) { return INTMIN; // Size mismatch }

int maxVal = INT
MIN; auto it1 = first1; auto it2 = first2; for (; it1 != last1 && it2 != last2; ++it1, ++it2) { if (it1 + it2 > maxVal) { maxVal = it1 + it2; } }

if (addDebugInfo) { int minVal = INT_MAX; it1 = first1; it2 = first2; for (; it1 != last1 && it2 != last2; ++it1, ++it2) { if (std::abs(it1 - it2) < minVal) { minVal = std::abs(it1 - it2); } } LOGGER->INFO(LOGGINGTYPE::Debug, "Minimum distance between the containers = %d", minVal); }

return maxVal; }