0

I am wanting to make a template function that adds three numbers. The type may be int or char or string. How can I add these then return the correct value using the same type. Example: three strings of numbers {5,6,7} should add up to 18 then return 18 as a string. three chars of numbers {5,6,7} should add up to 18 then return 18 as a char.

template <class MyType>
MyType GetSum (MyType a, MyType b, MyType c) {
  return (a+b+c);
}

  int a = 5, b = 6, c = 7, d; 
  char e = '5', f = '6', g = '7', h; 
  string i= "5", j= "6", k= "7", l; 

  d=GetSum<int>(a,b,c);
  cout << d << endl;

  h=GetSum<char>(e,f,g);
  cout << h << endl;

  l=GetSum<string>(i,j,k);
  cout << l << endl;

This code works for int but obviously not for char or string. I am not sure how to convert from an unknown type to int and back so i can add the numbers.

Cœur
  • 37,241
  • 25
  • 195
  • 267
user1082764
  • 1,973
  • 9
  • 26
  • 40
  • What's the sum of three chars? – Kerrek SB Sep 28 '13 at 18:40
  • http://stackoverflow.com/questions/1986418/typeid-and-typeof-in-c – Pier Sep 28 '13 at 18:43
  • What is "18 as a char"? – Kerrek SB Sep 28 '13 at 18:43
  • 1
    @user1082764: That's a *terrible* answer. Multibyte character constants are virtually useless. Their meaning is totally implementation-dependent and non-portable. – Kerrek SB Sep 28 '13 at 19:08
  • The return type of `GetSum` is `MyType`, or `char` for that particular instance. The type of `'18'` is not `char` (or, rather, I have never seen a compiler for which it is), so `'18'` cannot be the answer. However, `(char)18`, or `'\022'`, can. – anatolyg Sep 28 '13 at 19:35

3 Answers3

2

You want addition as if the items would be integers though may be int, char or std::string.

That means, first get them to be integers, then convert back to the original type:

template <typename T>
T sum(T t1, T t2, T t3)
{
   std::stringstream input;
   input << t1 << " " << t2 << " " << t3;
   int sum = 0;
   int item;
   while ( input >> item )
   {
      sum += item;
   }
   // at this point we have the wanted value as int, get it back in a general way:
   std::stringstream output;
   output << sum;
   T value;
   output >> value;
   return value;
}

I'd be a bit careful with the addition of chars in that way. '18' isn't exactly meaningful afaik, or probably at least platform dependent.

You'll need to include <sstream> in your project to use std::stringstream.

stefan
  • 10,215
  • 4
  • 49
  • 90
  • You are correct. It only displays the 1 in 18, not the full number. – user1082764 Sep 28 '13 at 19:29
  • Ah well that's a "flaw" in my code or rather a goodie that prevents everything from crashing. As `18` can't be stored in a single char, `output >> value` only puts the first character in `output` into `value`. – stefan Sep 28 '13 at 19:38
  • thanks for the help tho. this puts me a huge step in the right direction. – user1082764 Sep 28 '13 at 19:41
0

You can use boost::lexical_cast to convert between integer and string types.

template <class MyType>
MyType GetSum (MyType a, MyType b, MyType c)
{
    int int_a = boost::lexical_cast<int>(a);
    int int_b = boost::lexical_cast<int>(b);
    int int_c = boost::lexical_cast<int>(c);
    int sum = int_a+int_b+int_c;
    return boost::lexical_cast<MyType>(sum);
}

If you are not allowed, or don't want, to use boost, just implement the function template lexical_cast yourself (you will have to implement several template specializations, but each individual one is easy).

anatolyg
  • 26,506
  • 9
  • 60
  • 134
0

You can implement explicit conversion template functions, where each is implemented with template specialization. For instance:

template <typename MyType> int ToInt (MyType);
template <> int ToInt<int> (int x) { return x; }
template <> int ToInt<std::string> (std::string x) { return std::stoi(x); }
template <> int ToInt<char> (char x) { return std::stoi(std::string(&x, 1)); }

template <typename MyType> MyType FromInt (int);
template <> int FromInt<int> (int x) { return x; }
template <> std::string FromInt<std::string> (int x) {
    std::ostringstream oss;
    oss << x;
    return oss.str();
}
template <> char FromInt<char> (int x) {
    static const std::string map("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    return map.at(x);
}

Then, the GetSum() would call ToInt<>() on the arguments, compute the sum, and then call FromInt<>() to convert the value back to the original type:

template <typename MyType>
MyType GetSum (MyType a, MyType b, MyType c) {
    int aa = ToInt(a);
    int bb = ToInt(b);
    int cc = ToInt(c);
    return FromInt<MyType>(aa + bb + cc);
}

As can be seen in this demo, for your same program, the output is:

18
I
18

The reason for I for the char case is that the conversion assumes the resulting value can be expressed as a single base 36 digit.

jxh
  • 69,070
  • 8
  • 110
  • 193