jeudi 27 juin 2019

How can I set some predefined values for some values in a template function like with a #define?

I want to overload an operator (e.g. operator<<) with different types, but also change only 1 or 2 values in the function itself.

I want to get some fancy output of a vector with the primitive integer types. I have tried to create a template function like template<int width, typename T> operator<<... but this would need to set the width and typename explicitly with each call of the operator<< e.g.

I have a following minimal code example (which is not the shortest tbh):

main.cpp

#include <iostream>
#include <vector>

#include "utils.h"

using namespace std;

int main(int argc, char* argv[]) {
  vector<int8_t> vec_s_1 = {1, 2, 3, -1, -2, -123};
  vector<uint8_t> vec_u_1 = {1, 2, 3, 127, 128, 129};
  vector<int16_t> vec_s_2 = {1, 2, 3, -1, -2, -123};
  vector<uint16_t> vec_u_2 = {1, 2, 3, 127, 128, 129};
  vector<int32_t> vec_s_3 = {1, 2, 3, -1, -2, -123};
  vector<uint32_t> vec_u_3 = {1, 2, 3, 127, 128, 129};
  vector<int64_t> vec_s_4 = {1, 2, 3, -1, -2, -123};
  vector<uint64_t> vec_u_4 = {1, 2, 3, 127, 128, 129};

  cout << "vec_s_1: " << vec_s_1 << endl;
  cout << "vec_u_1: " << vec_u_1 << endl;
  cout << endl;
  cout << "vec_s_2: " << vec_s_2 << endl;
  cout << "vec_u_2: " << vec_u_2 << endl;
  cout << endl;
  cout << "vec_u_3: " << vec_u_3 << endl;
  cout << "vec_s_3: " << vec_s_3 << endl;
  cout << endl;
  cout << "vec_s_4: " << vec_s_4 << endl;
  cout << "vec_u_4: " << vec_u_4 << endl;

  return 0;
}

utils.h

#ifndef MODULO_SEQUENCE_UTILS_H
#define MODULO_SEQUENCE_UTILS_H

#include <vector>
#include <iomanip>
#include <ostream>
#include <sstream>

using namespace std;

template<typename T>
ostream& operator<<(ostream& os, const vector<T>& obj);

#endif // MODULO_SEQUENCE_UTILS_H

utils.cpp

#include "utils.h"

#define GET_FUNCTION(WIDTH, TYPENAME, MASK) \
template<> ostream& operator<<(ostream& os, const vector<TYPENAME>& obj) { \
  size_t size = obj.size(); \
  os << "["; \
  for (size_t i = 0; i < size; ++i) { \
    if (i > 0) { \
      os << ", "; \
    } \
    stringstream ss; \
    ss << "0x" << hex << uppercase << setw(WIDTH) << setfill('0') << (obj[i] & MASK); \
    os << ss.str(); \
  } \
  os << "]"; \
  return os; \
}

GET_FUNCTION(2, int8_t, 0xFF)
GET_FUNCTION(2, uint8_t, 0xFF)
GET_FUNCTION(4, int16_t, 0xFFFF)
GET_FUNCTION(4, uint16_t, 0xFFFF)
GET_FUNCTION(8, int32_t, 0xFFFFFFFF)
GET_FUNCTION(8, uint32_t, 0xFFFFFFFF)
GET_FUNCTION(16, int64_t, 0xFFFFFFFFFFFFFFFF)
GET_FUNCTION(16, uint64_t, 0xFFFFFFFFFFFFFFFF)

So far it is working like expected and the output is like I wanted to have it. It is solved by calling #define for each function separately (which is a really looking ugly code).

The output looks like this:

vec_s_1: [0x01, 0x02, 0x03, 0xFF, 0xFE, 0x85]
vec_u_1: [0x01, 0x02, 0x03, 0x7F, 0x80, 0x81]

vec_s_2: [0x0001, 0x0002, 0x0003, 0xFFFF, 0xFFFE, 0xFF85]
vec_u_2: [0x0001, 0x0002, 0x0003, 0x007F, 0x0080, 0x0081]

vec_u_3: [0x00000001, 0x00000002, 0x00000003, 0x0000007F, 0x00000080, 0x00000081]
vec_s_3: [0x00000001, 0x00000002, 0x00000003, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFF85]

vec_s_4: [0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFF85]
vec_u_4: [0x0000000000000001, 0x0000000000000002, 0x0000000000000003, 0x000000000000007F, 0x0000000000000080, 0x0000000000000081]

I need the different widths of the leading zeros in the output plus the mask for getting the exact hex number for each type.

My question is: How can/could I achieve the same result with only using templates?

Aucun commentaire:

Enregistrer un commentaire