I am trying to write a template function that attempts to convert anything into a long.
.h

class General
{
public:
static void delay( int seconds );
 
 
template <typename Generic> static long ToLong( Generic source );
template <typename Generic> static double ToDouble( Generic source );
template <typename Generic> static int ToInt( Generic source );
};

.cpp

void General::delay( int seconds )
{ 
#ifdef WIN32
Sleep( seconds * 1000 );
#else
sleep ( seconds );
#endif
 
 
}
template <typename Generic> long General::ToLong( Generic source )
{
if ( strcmp( typeid( source).name(), "long" ) == 0 )
return source;
 
long a=0;
istringstream o;
o.str(source);
if ( ! (o>>a ))
throw DHException( "StringUtils", "Could not convert [" + source + "] to a long!");
return a;
}

The problem occurs when I attempt to call it but actually pass it something that is already a long:

long temp=5;
long temp2 = General::ToLong( temp )

"../libs/General.cpp", line 22: Error: Could not find a match for std::basic_istringstream<char, std::char_traits<char>, std::allocator<char>>::str(long).
"Hoff.cpp", line 66: Where: While instantiating "static General::ToLong<long>(long)".
"Hoff.cpp", line 66: Where: Instantiated from non-template code.


How do I detect that it is already a long and simply return itself? (Ignore the part about the DHException for now..)

Isn't the error related to trying to create a string from a long value?

This may not be the best fix, but FWIW.

ostringstream i; // ;)
   i << source;
   istringstream o;
   o.str(i.str());

That's why I'm trying to detect that it's a long and not do anything except return it. (I tried with the typeid stuff but it doesn't seem to detect it...)

Seems kind of silly to take a long, convert it to a string, just to convert it back to a long! Also, by the way, I realize my example looks silly as I am explicitly passing a long to a function that converts to a long. This is a simplified version. (The real version is that I'm using another templated class which has a function that returns a long and inside it's implementation it uses this convert function).

Dave,

What you suggested works. Note that at runtime it ends up just returning the source rather than doing the ostringstream or istringstream stuff. (which is good)

template <typename Generic> long General::ToLong( Generic source )
{
   if ( strcmp( typeid(source).name(), "long") == 0 )
   {
     return source;
   }
 
   long a=0;
   ostringstream i; // ;)
   i << source;
   istringstream o;
   o.str(i.str());
   if ( ! (o>>a ))
  throw DHException( "General", "Could not convert [" + o.str() + "] to a long!");
 return a;
}

<< moderator edit: added code tags: [code][/code] >>

Actually, I take that back. When I attempt to use it with string, it complains about the first part. In effect, it looks like the compiler ignores anything to do with the typeid check and assumes you will do either case...

Use template specialization instead?

#include <iostream>
#include <cstring>
#include <sstream>
#include <string>
using namespace std;

template <typename T> 
long ToLong( T source )
{
   long a=0;
   ostringstream oss;
   oss << source;
   istringstream iss(oss.str());
   if ( ! (iss >> a ) )
   {
      //throw DHException( "StringUtils", "Could not convert [" + source + "] to a long!");
   }
   return a;
}

template <long> 
long ToLong( long source )
{
   return source;
}

int main()
{
   long temp=5;
   long temp2 = ToLong( temp );
   cout << temp2 << endl;

   string s("123");
   long value = ToLong(s);
   cout << value << endl;
   return 0;
}

/* my output
5
123
*/

Didn't know you could do that. Man, I'm learning a lot from this forum... Appreciate the help on both this and other questions, Dave.

Dave,

I used your suggestion, though I hit a wrinkle. I have toInt and toDouble functions as well. I got a compiler error when doing the ToInt..

template <double> double ToDouble( double source )
{
return source;
}

line 35: Error: Template parameters cannot have type double.

template <> double ToDouble( double source )
{
  return source;
}

Dogtree - it doesn't like it in my .h file because my function is static. Says:

Error: "static" is not allowed here.

That's because it's not allowed there. :rolleyes: Using static to qualify functions is deprecated anyway, use an unnamed namespace instead:

namespace {
  template <> double ToDouble( double source )
  {
    return source;
  }
}

Actually, turns out that I don't need to use templates at all when passing the double or the long... It uses the first function if I pass it a double, it uses the second if I pass it anything else...

double General::ToDouble( double source )
{
 cout<<"IN BASIC DOUBLE FUNCTION"<<endl;
   return source;
} 
template <typename Generic> double General::ToDouble( Generic source )
{
 
   double a=0;
   ostringstream i; // ;)
   i << source;
   istringstream o;
   o.str(i.str());
   if ( ! (o>>a ))
  throw DHException( "General", "Could not convert [" + o.str() + "] to a double!");
 return a;
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.