Thread: Function template specialization?

  1. #1
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545

    Function template specialization?

    When compiling this code on VC++ 6.0 it gives me:
    Code:
    error C2667: 'StringToNum' : none of 2 overload have a best conversion
    error C2668: 'StringToNum' : ambiguous call to overloaded function
    Code:
    #include <string>
    #include <sstream>
    #include <stdexcept>
    #include <climits>
    
    template <typename E,
              typename T,
              typename A,
              typename N>
    void StringToNum( const std::basic_string<E, T, A>&  str,
                                                     N&  num )
    {
        std::basic_stringstream<E, T, A> ss( str );
    
        if ( !(ss >> num) )
        {
            throw std::invalid_argument( "Error converting string to number!" );
        }
    }
    
    template <typename E,
              typename T,
              typename A>
    void StringToNum( const std::basic_string<E, T, A>&  str,
                                         unsigned char&  num )
    {
        std::basic_stringstream<E, T, A> ss( str );
        unsigned short snum = 0;
    
        if ( !(ss >> snum) || (snum > UCHAR_MAX) )
        {
            throw std::invalid_argument( "Error converting string to number!" );
        }
        num = static_cast<unsigned char>( snum );
    }
    
    using namespace std;
    
    int main()
    {
        unsigned char num = 0;
        wstring str( L"Hello world" );
        StringToNum( str, num );
        return 0;
    }
    and on Comeau it's quite a bit more verbose...
    What's wrong and how can I make StringToNum() work for unsigned char numbers?

    When I tried compiling it without the specialization for unsigned chars I got this error:
    Code:
    error C2679: binary '>>' : no operator defined which takes a right-hand operand of type 'char' (or there is no acceptable conversion)
            D:\Programming\C++\Test\src\main.cpp(15) : see reference to function template instantiation 'class std::basic_istream<unsigned short,struct std::char_traits<unsigned short> > &__cdecl std::operator >>(class std::basic_istream<unsigned short,
    struct std::char_traits<unsigned short> > &,unsigned char &)' being compiled

  2. #2
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    What function would the compiler choose if on the following template N was a unsigned char?

    Code:
    template <typename E,
              typename T,
              typename A,
              typename N>
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  3. #3
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Mario F. View Post
    What function would the compiler choose if on the following template N was a unsigned char?

    Code:
    template <typename E,
              typename T,
              typename A,
              typename N>
    Since I provided a function that excplicitely takes an unsigned char, shouldn't it choose that one?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I tested cpjust's original code example with the MinGW port of g++ 3.4.5 and MSVC8, and it compiled without even a warning in both cases. However, it ran with an segfault in both cases too.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    I believe he should do a partial specialization of the first template to take a unsigned char&.

    Code:
    template <typename E,
              typename T,
              typename A>
    void StringToNum<typename E, typename T, typename A, unsigned char&>( const std::basic_string<E, T, A>&  str, unsigned char&  num ) {
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  6. #6
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by laserlight View Post
    I tested cpjust's original code example with the MinGW port of g++ 3.4.5 and MSVC8, and it compiled without even a warning in both cases. However, it ran with an segfault in both cases too.
    Try using Comeau. It gives you pages of errors.

  7. #7
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Mario F. View Post
    I believe he should do a partial specialization of the first template to take a unsigned char&.

    Code:
    template <typename E,
              typename T,
              typename A>
    void StringToNum<typename E, typename T, typename A, unsigned char&>( const std::basic_string<E, T, A>&  str, unsigned char&  num ) {
    That didn't work. This is on VC++ 6.0, so maybe that has something to do with it also...

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I believe he should do a partial specialization of the first template to take a unsigned char&.
    From what I understand C++ does not have partial function template specialisation at the moment.

    Try using Comeau. It gives you pages of errors.
    Yes, I did. I wanted to point out an inconsistency here with two other compilers that are reasonably standard conformant.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Quote Originally Posted by cpjust View Post
    That didn't work.
    Nor it should. I'm sorry. Copyed paste code in a whim and didn't check my post properly. If anything you wouldn't need the arguments declaration. But you have a function template there. Not a class template. So I did even worst, function templates can't be partially specialized.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  10. #10
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by laserlight View Post
    I tested cpjust's original code example with the MinGW port of g++ 3.4.5 and MSVC8, and it compiled without even a warning in both cases. However, it ran with an segfault in both cases too.
    Oh, I think I might know why it crashed. Change the string to "255" instead of "Hello world".

    Anyways, I found a workable, but slightly less desirable solution:
    Code:
    template <typename E,
              typename T,
              typename A,
              typename N>
    void StringToNum( const std::basic_string<E, T, A>&  str,
                                                     N&  num )
    {
        std::basic_stringstream<E, T, A> ss( str );
        long lnum = 0;
    
        if ( !(ss >> lnum) || (lnum < std::numeric_limits<N>::min()) || (lnum > std::numeric_limits<N>::max()) )
        {
            throw std::invalid_argument( "Error converting string to number!" );
        }
    
    	num = static_cast<N>( lnum );
    }
    BTW, I tried using long long int lint = 0; but VC++ 6.0 said I can't say long twice.
    I've seen that used in other examples to get 64-bit integers... Is long long standard, or is it a compiler extension?

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    __int64 would do the trick on Microsoft compilers.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    It's currently an extension on some C++ compilers.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  13. #13
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    There probably isn't a basic_stringstream overload for operator>>() for 64-bit ints anyways, so maybe I'd better keep it as a long.

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Sure, there is.
    Code:
    std::stringstream s;
    s << (uint64_t)0; // Works
    s << (int64_t)0; // Works
    uint64_t n;
    s >> n; // Works
    s >> (int64_t)n; // Doesn't work! :(
    At least on Microsoft's compilers.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Elysia View Post
    Sure, there is.
    Code:
    std::stringstream s;
    s << (uint64_t)0; // Works
    s << (int64_t)0; // Works
    uint64_t n;
    s >> n; // Works
    s >> (int64_t)n; // Doesn't work! :(
    At least on Microsoft's compilers.
    I think they key phrase there is "At least on Microsoft's compilers".
    I tried using a long long with stringstreams on Comeau and it didn't have an operator>>() for long long.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  2. <Gulp>
    By kryptkat in forum Windows Programming
    Replies: 7
    Last Post: 01-14-2006, 01:03 PM
  3. Post...
    By maxorator in forum C++ Programming
    Replies: 12
    Last Post: 10-11-2005, 08:39 AM
  4. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  5. C++ compilation issues
    By Rupan in forum C++ Programming
    Replies: 1
    Last Post: 08-22-2005, 05:45 AM