Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent duplicated code on different data types (uint16_t/ uint32_t)

Tags:

c++

I'm looking for a possibility for using a function where I pass a pointer to uint16_t or uint32_t values.

Currently I use the two overloaded functions

std::vector<float> calcMap(uint16_t* map)
std::vector<float> calcMap(uint32_t* map)

Since they return float values the calculation is the same for 16 and 32 bit values. The only difference is the data type which is needed to go through the array pointed to. I don't want to have the whole content of the function twice, is there a possibility to make it type independent?

like image 390
A. R. Avatar asked Jan 29 '23 09:01

A. R.


2 Answers

Mostly for completeness:

In case you don't want to expose the implementation of the functions, and for whatever reason don't want to forward to a private template. There's the oft overlooked option of explicit template instantiation declarations. It's rather easy:

  1. Declare a template, and explicitly declare the instantiations of it in a header:

    template<typename T> std::vector<float> calcMap(T*);
    extern template std::vector<float> calcMap<>(uint16_t*);
    extern template std::vector<float> calcMap<>(uint32_t*);
    
  2. In your own original translation unit, define one template, and add two explicit instantiations:

    template<typename T>
    std::vector<float> calcMap(T*) {
      // Now we implement
    }
    
    template std::vector<float> calcMap<>(uint16_t*); // Now this will link
    template std::vector<float> calcMap<>(uint32_t*); // As will this
    

How is it different from drescherjm's excellent suggestion? It will produce less symbols. And in case your compiler isn't too good at link time inlining, it won't require it to skip the forwarding functions.

like image 164
StoryTeller - Unslander Monica Avatar answered Feb 08 '23 17:02

StoryTeller - Unslander Monica


If you only want to accept uint16_t and uint32_t, then something along the following lines should work:

template <class T,
  class = typename std::enable_if<
    std::is_same<typename std::decay<T>::type, uint16_t>::value || 
    std::is_same<typename std::decay<T>::type, uint32_t>::value>::type>
std::vector<float> calcMap(T * map) {
  // Code
}

You have to #include <type_traits> and enable at least C++11 for the above to work.

By the way, if your code only reads the data, then changing T * into T const * might be a good idea. Or hell, T const * const while you're at it.

You might also be interested in std::is_integral, in case you just want to allow more than the 2 types used above.

like image 42
AVH Avatar answered Feb 08 '23 17:02

AVH