1

Type traits to get result of promotion from operator

A follow up question for this is there a good way to do this with only using C++98 no boost?

Community
  • 1
  • 1
IdeaHat
  • 7,641
  • 1
  • 22
  • 53

3 Answers3

3

So long as you only need to worry about the standard built-in types, you can do it like so:

template <int> struct plus_helper;
template <> struct plus_helper< 1> { typedef char type; };
template <> struct plus_helper< 2> { typedef signed char type; };
template <> struct plus_helper< 3> { typedef unsigned char type; };
template <> struct plus_helper< 4> { typedef short type; };
template <> struct plus_helper< 5> { typedef unsigned short type; };
template <> struct plus_helper< 6> { typedef int type; };
template <> struct plus_helper< 7> { typedef unsigned int type; };
template <> struct plus_helper< 8> { typedef long type; };
template <> struct plus_helper< 9> { typedef unsigned long type; };
template <> struct plus_helper<10> { typedef float type; };
template <> struct plus_helper<11> { typedef double type; };
template <> struct plus_helper<12> { typedef long double type; };
template <> struct plus_helper<13> { typedef wchar_t type; };

template <typename T1, typename T2>
struct plus {
private:
  static char (&f(char))[1];
  static char (&f(signed char))[2];
  static char (&f(unsigned char))[3];
  static char (&f(short))[4];
  static char (&f(unsigned short))[5];
  static char (&f(int))[6];
  static char (&f(unsigned int))[7];
  static char (&f(long))[8];
  static char (&f(unsigned long))[9];
  static char (&f(float))[10];
  static char (&f(double))[11];
  static char (&f(long double))[12];
  static char (&f(wchar_t))[13];
public:
  typedef typename plus_helper<sizeof(f(*(T1*)0 + *(T2*)0))>::type type;
};

template <typename T1, typename T2>
struct plus<T1 *, T2> {
  typedef T1 *type;
};

template <typename T1, typename T2>
struct plus<T1, T2 *> {
  typedef T2 *type;
};

Note that I've required that T1 and T2 can be added. No error is necessarily given if they cannot be. Note also that I've not omitted the shorter-than-int types. They can never be returned by the built-in + operator, but they're valid return types for a custom operator+.

Unfortunately, if you also need to worry about other types, such as custom structures, this approach isn't going to work, and while I would be happy to be proven wrong, I don't think it's possible to make that work.

0

Probably not the best way, but this is what i got...

template <bool value,typename T,typename J>
struct conditional{typedef T type;};

template <typename T,typename J>
struct conditional<false,T,J>{typedef J type;};

template <typename T, typename J>
struct is_equal
{
  enum {value = false};
};

template <typename T>
struct is_equal<T,T>
{
  enum {value = true};
};

namespace
{
template <typename T, typename J, typename K, typename L>
struct math_t
{
  typedef typename conditional<
    is_equal<T,K>::value || is_equal<J,K>::value,
    K,
    L>::type type;
};
}
template <typename T, typename J>
struct math_type
{
  typedef typename math_t<T,J,long double,
  typename math_t<T,J,double,
  typename math_t<T,J,float,
  typename math_t<T,J,long long unsigned int,
  typename math_t<T,J,long long int,
  typename math_t<T,J,long unsigned int,
  typename math_t<T,J,long int,
  typename math_t<T,J,unsigned int,
  int>::type>::type>::type>::type>::type>::type>::type>::type type;
};
IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • Consider what happens when you add a `long int` and an `unsigned int`. The result depends on the implementation, but on my system, it is `unsigned long int`, which is not what your template gives. –  Apr 15 '14 at 14:31
0

I covered a similar issue here: https://stackoverflow.com/a/2450157/34509 . Repasting my code because this seems to be what you are after. Please see the referred answer for a detailed explanation

// typedef eiher to A or B, depending on what integer is passed
template<int, typename A, typename B>
struct cond;

#define CCASE(N, typed) \
  template<typename A, typename B> \
  struct cond<N, A, B> { \
    typedef typed type; \
  }

CCASE(1, A); CCASE(2, B);
CCASE(3, int); CCASE(4, unsigned int);
CCASE(5, long); CCASE(6, unsigned long);
CCASE(7, float); CCASE(8, double);
CCASE(9, long double);

#undef CCASE

// for a better syntax...
template<typename T> struct identity { typedef T type; };

// different type => figure out common type
template<typename A, typename B>
struct promote {
private:
  static A a;
  static B b;

  // in case A or B is a promoted arithmetic type, the template
  // will make it less preferred than the nontemplates below
  template<typename T>
  static identity<char[1]>::type &check(A, T);
  template<typename T>
  static identity<char[2]>::type &check(B, T);

  // "promoted arithmetic types"
  static identity<char[3]>::type &check(int, int);
  static identity<char[4]>::type &check(unsigned int, int);
  static identity<char[5]>::type &check(long, int);
  static identity<char[6]>::type &check(unsigned long, int);
  static identity<char[7]>::type &check(float, int);
  static identity<char[8]>::type &check(double, int);
  static identity<char[9]>::type &check(long double, int);

public:
  typedef typename cond<sizeof check(0 ? a : b, 0), A, B>::type
    type;
};

// same type => finished
template<typename A>
struct promote<A, A> {
  typedef A type;
};

For example

int main() {
  promote<char, short>::type a;
  int *p0 = &a;

  promote<float, double>::type b;
  double *p1 = &b;

  promote<char*, string>::type c;
  string *p2 = &c;
}
Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212