1

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:
ckruczek
  • 2,361
  • 2
  • 20
  • 23
StoneThrow
  • 5,314
  • 4
  • 44
  • 86

2 Answers2

6

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 >>.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • That's pretty clever and exposes something else I am unfamiliar with due to lack of use: the `>>` operator. So if I interpret this correctly, `istringstream::>>` operator will "attempt to" parse the string into its right hand operand - is that right? – StoneThrow Jul 20 '17 at 06:49
  • 1
    @StoneThrow - `operator>>` is in fact a special function name. C++ code can implement it for user defined types and it will be chosen in overload restitution when `A >> B` is written with those types. The standard stream classes (being user defined) already overload them to allow "input" of all fundamental types. But if you write your class, you can add a `operator>>(istream&, myClass&)` function yourself. And yes, if the required parsing fails, the parser state will return `fail() == true`. – StoryTeller - Unslander Monica Jul 20 '17 at 06:53
  • Problem with that solution: `is("1976 Dodge Van")` is `true`. You might want to change that to `!parser.fail() && parser.eof()` - I'm not quite sure though that there isn't another stream states "detail" lurking. – peterchen Jul 20 '17 at 07:22
  • @peterchen - There probably is. I never could remember the various meanings of the state bit combinations. This is a fairly naive solution, I admit. – StoryTeller - Unslander Monica Jul 20 '17 at 07:24
3

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

K. Kirsz
  • 1,384
  • 10
  • 11
  • 1
    If I may make a suggestion. You can add `= delete` to the primary template. That will give a decent error early during compile time (as opposed to link time) that the type isn't supported. – StoryTeller - Unslander Monica Jul 20 '17 at 06:45
  • One thing I learned from this is that the "function prototype" or "unspecialized template prototype" is required. (what is the correct term for line 4 of your code?). As opposed to an equivalent non-template function where the prototype would not be needed if is parsed before its use. – StoneThrow Jul 20 '17 at 06:46
  • 1
    @StoryTeller I didn't know that this was possible - good to know. Thank you for the hint. – Simon Kraemer Jul 20 '17 at 06:49