StoneThrow
StoneThrow

Reputation: 6285

Template functions to check "is int"/"is double"/etc

I am a bit shaky with C++ template syntax, so I'm not sure if what I'm envisioning is possible, and if it is, I'm unclear on correct syntax.

I would like to implement template functions like template<int> bool is( std::string& ), template<double> bool is( std::string& ), etc. so that I can call is <int> (...) or is <double> (...) instead of isInt(...) or isDouble(...), etc. Is this possible? If so, how would you code the function signatures?

With my tenuous grasp of template syntax, my attempt was:

#include <iostream>
#include <cstdlib>

template<int>
bool is( std::string& raw )
{
    if ( raw.empty() ) return false;
    char* p;
    int num = strtol( raw.c_str(), &p, 10);
    return ( ( *p != '\0' ) ? false : true );
}

int main( int argc, char* argv[] )
{
    std::string str("42");
    std::cout << std::boolalpha << is <int> ( str ) << std::endl;
    return 0;
}

This failed with the following errors:

>g++ -g main.cpp
main.cpp: In function ‘int main(int, char**)’:
main.cpp:16:51: error: no matching function for call to ‘is(std::string&)’
     std::cout << std::boolalpha << is <int> ( str ) << std::endl;
                                                   ^
main.cpp:5:6: note: candidate: template<int <anonymous> > bool is(std::string&)
 bool is( std::string& raw )
      ^
main.cpp:5:6: note:   template argument deduction/substitution failed:

Upvotes: 1

Views: 300

Answers (2)

My comment to your post withstanding, the way to do this easily is with a simple template that uses the std::istringstream class to parse:

template<typename T>
bool is(std::string const& raw) {
  std::istringstream parser(raw);

  T t; parser >> t;
  return !parser.fail() && parser.eof();
}

The obvious caveat is that T must be default constructable. But on the plus side, the above will work for user defined types as well, so long as they implement operator >>.

Upvotes: 6

K. Kirsz
K. Kirsz

Reputation: 1420

You need to use template specialisation for this:

#include <iostream>
#include <cstdlib>

template<class T> bool is(std::string& raw) = delete;

template<>
bool is<int>( std::string& raw )
{
    if ( raw.empty() ) return false;
    char* p;
    int num = strtol( raw.c_str(), &p, 10);
    return ( ( *p != '\0' ) ? false : true );
}

int main( int argc, char* argv[] )
{
    std::string str("42");
    std::cout << std::boolalpha << is <int> ( str ) << std::endl;
    return 0;
}

You can read more about in here

Upvotes: 3

Related Questions