-1

If I have a complicated function that I want to use for two collections with matching interfaces (at least as far as the function in question is concerned) is there a way to just re-use the template code?

For example:

void DoSomethingIntense(std::vector<blah> myBlah);
void DoSomethingIntense(std::array<blah> myBlah);

If I use begin, end, size, and other functions that both array and vector have in common, is there a way to re-use the body of DoSomethingIntense without typing it twice (or, heaven forbid, stuffing it into a macro)?

(Please do not nitpick the example code, it doesn't help anybody)

UPDATE: My apologies, I neglected to mention that the function in question has other implementations for classes that do not match this signature; just making every argument use the code that works for these two is not an option.

I think the iterator solution might be best in that scenario.

3 Answers3

3

Yes, use a template.

template <typename Container>
void DoSomethingIntense(Container blah) {  // Might be better as Container const &
    // write code using blah.begin() or whatever
}

You might be able to make it even more generic, following the example of STL, by supporting a general iterator range rather than specifically a container:

template <typename Iterator>
void DoSomethingIntense(Iterator begin, Iterator end);
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

Yes, you can achieve that by using templates:

template<typename T>
void DoSomethingIntense(const T &myBlah);

EDIT:

If I get your update right then I would say make use of SFINEA:

template<typename T>
struct is_vector : std::false_type {};

template<typename T, typename A>
struct is_vector<std::vector<T, A>> : std::true_type {};

template<typename T>
struct is_array : std::false_type {};

template<typename T, size_t N>
struct is_array<std::array<T, N>> : std::true_type {};

// add more if you want or define a macro

template<typename T>
std::enable_if_t<is_vector<T>::value || is_array<T>::value, void>
DoSomethingIntense(const T &myBlah)
{
}

int main()
{
    std::vector<int> v;
    DoSomethingIntense(v); // OK

    std::array<float, 5> a;
    DoSomethingIntense(a); // OK

    std::queue<int> q;
    DoSomethingIntense(q); // ERROR
}
Axalo
  • 2,953
  • 4
  • 25
  • 39
0

You can mix templates / overloads. No problem.

For example:

template <typename T> 
void DoSomethingIntense(T myBlah) {

}

void DoSomethingIntense(MyCustomClass myBlah) {

}

Then it will use the non-template version for argument type MyCustomClass and the template version for anything else (like vector or array)

Moreover, you can use std::enable_if to restrict the range of possible template arguments. See also this question.

Community
  • 1
  • 1
manuel
  • 533
  • 6
  • 16