Portable list of unsigned integer types

Discussion in 'C++' started by Fred Zwarts, Oct 13, 2009.

  1. Fred Zwarts

    Fred Zwarts Guest

    I have created a template function for a generic algorithm.
    For unsigned integer types, a small modification in the algorithm is needed,
    because I can't use negative values there.
    So, I want to make specializations for all unsigned integer types.
    I assume that it is not possible in C++ to write one specialization for all
    unsigned integer type, but that a specialization for each unsigned integer type
    must be created.
    Since this software runs on different platforms, I wonder whether it is
    possible to write a complete set of specializations in a platform independent way.

    I first tried to write specializations for uint8_t, uint16_t, uint32_t and uint64_t
    as defined in inttypes.h, but it turns out that on some platforms some
    unsigned integer types are still missing. (Under Windows e.g.,
    there is more than one 32-bit unsigned integer type.)
    Types like size_t and clock_t map to different types on different platforms.
    I wonder whether it is possible to create a complete list,
    without using conditional code selection in the preprocessor.
    Is the list "unsigned char, unsigned short, unsigned int, unsigned long and unsigned long long"
    complete and without overlap (as far as specializations concern) for all platforms?
    Should I add unsigned wchar_t, or is it covered already?

    (I know that char needs special attention. I know how to handle that case.)
     
    Fred Zwarts, Oct 13, 2009
    #1
    1. Advertising

  2. "Fred Zwarts" <> wrote:
    > I have created a template function for a generic algorithm.
    > For unsigned integer types, a small modification in the algorithm is needed,
    > because I can't use negative values there.
    > So, I want to make specializations for all unsigned integer types.
    > I assume that it is not possible in C++ to write one specialization for all
    > unsigned integer type, but that a specialization for each unsigned integer type
    > must be created.
    > Since this software runs on different platforms, I wonder whether it is
    > possible to write a complete set of specializations in a platform independent way.
    >
    > I first tried to write specializations for uint8_t, uint16_t, uint32_t and uint64_t
    > as defined in inttypes.h, but it turns out that on some platforms some
    > unsigned integer types are still missing. (Under Windows e.g.,
    > there is more than one 32-bit unsigned integer type.)
    > Types like size_t and clock_t map to different types on different platforms.
    > I wonder whether it is possible to create a complete list,
    > without using conditional code selection in the preprocessor.
    > Is the list "unsigned char, unsigned short, unsigned int, unsigned long and unsigned long long"
    > complete and without overlap (as far as specializations concern) for all platforms?
    > Should I add unsigned wchar_t, or is it covered already?
    >
    > (I know that char needs special attention. I know how to handle that case.)


    Your list seems exhaustive, and "unsigned wchar_t" should be already
    covered by your list (after all, it should be just an unsigned integer
    somewhat bigger than char). But you'll eventually get more certain
    answers about this.

    About avoiding to create all those specializations, can you get along
    with duplicating the body of your template to include both algorithms,
    checking then for unsigned-ness at runtime via numeric_limits?

    The compiler could then optimize away the algorithm version that
    doesn't happen to be appropriate for each type - at least, I suppose
    so, I'd have to check if it works but I'm not so sure I will able to.

    Just an idea off the top of my head.

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 13, 2009
    #2
    1. Advertising

  3. On 13 Ott, 12:45, "Francesco S. Carta" <> wrote:
    > "Fred Zwarts" <> wrote:
    > > I have created a template function for a generic algorithm.
    > > For unsigned integer types, a small modification in the algorithm is needed,
    > > because I can't use negative values there.
    > > So, I want to make specializations for all unsigned integer types.
    > > I assume that it is not possible in C++ to write one specialization for all
    > > unsigned integer type, but that a specialization for each unsigned integer type
    > > must be created.
    > > Since this software runs on different platforms, I wonder whether it is
    > > possible to write a complete set of specializations in a platform independent way.

    >
    > > I first tried to write specializations for uint8_t, uint16_t, uint32_t and uint64_t
    > > as defined in inttypes.h, but it turns out that on some platforms some
    > > unsigned integer types are still missing. (Under Windows e.g.,
    > > there is more than one 32-bit unsigned integer type.)
    > > Types like size_t and clock_t map to different types on different platforms.
    > > I wonder whether it is possible to create a complete list,
    > > without using conditional code selection in the preprocessor.
    > > Is the list "unsigned char, unsigned short, unsigned int, unsigned long and unsigned long long"
    > > complete and without overlap (as far as specializations concern) for all platforms?
    > > Should I add unsigned wchar_t, or is it covered already?

    >
    > > (I know that char needs special attention. I know how to handle that case.)

    >
    > Your list seems exhaustive, and "unsigned wchar_t" should be already
    > covered by your list (after all, it should be just an unsigned integer
    > somewhat bigger than char). But you'll eventually get more certain
    > answers about this.
    >
    > About avoiding to create all those specializations, can you get along
    > with duplicating the body of your template to include both algorithms,
    > checking then for unsigned-ness at runtime via numeric_limits?
    >
    > The compiler could then optimize away the algorithm version that
    > doesn't happen to be appropriate for each type - at least, I suppose
    > so, I'd have to check if it works but I'm not so sure I will able to.


    Sorry, I badly worded it because it's not that clear to me. Maybe that
    check will be performed at compile-time (otherwise, the compiles
    wouldn't be able to optimize away those parts).

    Something new to experiment ;-)

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 13, 2009
    #3
  4. Fred Zwarts

    Kai-Uwe Bux Guest

    Fred Zwarts wrote:

    > I have created a template function for a generic algorithm.
    > For unsigned integer types, a small modification in the algorithm is
    > needed, because I can't use negative values there.
    > So, I want to make specializations for all unsigned integer types.


    Maybe the following helps:

    template < typename T >
    struct is_signed {
    static bool const value = 0 > T(-1);
    };

    > I assume that it is not possible in C++ to write one specialization for
    > all unsigned integer type, but that a specialization for each unsigned
    > integer type must be created.


    No, but you could do:

    template < typename T, bool IsSigned = is_signed<T>::value >
    struct ...

    and partially specialize that for <T,true> and <T,false>.

    [...]


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 13, 2009
    #4
  5. Fred Zwarts

    Fred Zwarts Guest

    Kai-Uwe Bux wrote:
    > Fred Zwarts wrote:
    >
    >> I have created a template function for a generic algorithm.
    >> For unsigned integer types, a small modification in the algorithm is
    >> needed, because I can't use negative values there.
    >> So, I want to make specializations for all unsigned integer types.

    >
    > Maybe the following helps:
    >
    > template < typename T >
    > struct is_signed {
    > static bool const value = 0 > T(-1);
    > };
    >
    >> I assume that it is not possible in C++ to write one specialization
    >> for all unsigned integer type, but that a specialization for each
    >> unsigned integer type must be created.

    >
    > No, but you could do:
    >
    > template < typename T, bool IsSigned = is_signed<T>::value >
    > struct ...
    >
    > and partially specialize that for <T,true> and <T,false>.
    >
    > [...]


    I tried something along these lines, but it turned out to my surprise,
    that partial specializations are not allowed for template functions,
    only for template classes/structs. Of course I could encapsulate the
    function in a class and add a wrapper function...
     
    Fred Zwarts, Oct 13, 2009
    #5
  6. Fred Zwarts

    Fred Zwarts Guest

    Francesco S. Carta wrote:
    > "Fred Zwarts" <> wrote:
    >> I have created a template function for a generic algorithm.
    >> For unsigned integer types, a small modification in the algorithm is
    >> needed,
    >> because I can't use negative values there.
    >> So, I want to make specializations for all unsigned integer types.
    >> I assume that it is not possible in C++ to write one specialization
    >> for all
    >> unsigned integer type, but that a specialization for each unsigned
    >> integer type
    >> must be created.
    >> Since this software runs on different platforms, I wonder whether it
    >> is
    >> possible to write a complete set of specializations in a platform
    >> independent way.
    >>
    >> I first tried to write specializations for uint8_t, uint16_t,
    >> uint32_t and uint64_t
    >> as defined in inttypes.h, but it turns out that on some platforms
    >> some
    >> unsigned integer types are still missing. (Under Windows e.g.,
    >> there is more than one 32-bit unsigned integer type.)
    >> Types like size_t and clock_t map to different types on different
    >> platforms.
    >> I wonder whether it is possible to create a complete list,
    >> without using conditional code selection in the preprocessor.
    >> Is the list "unsigned char, unsigned short, unsigned int, unsigned
    >> long and unsigned long long" complete and without overlap (as far as
    >> specializations concern) for all platforms?
    >> Should I add unsigned wchar_t, or is it covered already?
    >>
    >> (I know that char needs special attention. I know how to handle that
    >> case.)

    >
    > Your list seems exhaustive, and "unsigned wchar_t" should be already
    > covered by your list (after all, it should be just an unsigned integer
    > somewhat bigger than char). But you'll eventually get more certain
    > answers about this.
    >
    > About avoiding to create all those specializations, can you get along
    > with duplicating the body of your template to include both algorithms,
    > checking then for unsigned-ness at runtime via numeric_limits?
    >
    > The compiler could then optimize away the algorithm version that
    > doesn't happen to be appropriate for each type - at least, I suppose
    > so, I'd have to check if it works but I'm not so sure I will able to.
    >
    > Just an idea off the top of my head.


    Thanks for the suggestion. I tried something along these lines.
    It compiles and works as expected, but some compilers generate a lot
    of warnings for those lines where tests are made for the sign of the
    values during instantiations of unsigned types. Since this header is
    included in may modules, I get many warnings which I cannot suppress
    and which makes it difficult to find the more relevant warnings.
     
    Fred Zwarts, Oct 13, 2009
    #6
  7. Fred Zwarts

    Kai-Uwe Bux Guest

    Fred Zwarts wrote:

    > Kai-Uwe Bux wrote:

    [...]
    >> No, but you could do:
    >>
    >> template < typename T, bool IsSigned = is_signed<T>::value >
    >> struct ...
    >>
    >> and partially specialize that for <T,true> and <T,false>.
    >>
    >> [...]

    >
    > I tried something along these lines, but it turned out to my surprise,
    > that partial specializations are not allowed for template functions,
    > only for template classes/structs. Of course I could encapsulate the
    > function in a class and add a wrapper function...


    Yup. That is annoying. Maybe the most prominent case is specializing a
    generic algorithm to take advantage of random access iterators. You have to
    wrap the algorithm as a static member function of a class template, which
    you can specialize in turn. I don't know why one has to go through the
    extra complexity. (Come to think of it, I don't know whether this is slated
    to change in C++0X.)


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 13, 2009
    #7
  8. "Fred Zwarts" <> wrote:
    > Francesco S. Carta wrote:
    > > "Fred Zwarts" <> wrote:
    > >> I have created a template function for a generic algorithm.
    > >> For unsigned integer types, a small modification in the algorithm is
    > >> needed,
    > >> because I can't use negative values there.
    > >> So, I want to make specializations for all unsigned integer types.
    > >> I assume that it is not possible in C++ to write one specialization
    > >> for all
    > >> unsigned integer type, but that a specialization for each unsigned
    > >> integer type
    > >> must be created.
    > >> Since this software runs on different platforms, I wonder whether it
    > >> is
    > >> possible to write a complete set of specializations in a platform
    > >> independent way.

    >
    > >> I first tried to write specializations for uint8_t, uint16_t,
    > >> uint32_t and uint64_t
    > >> as defined in inttypes.h, but it turns out that on some platforms
    > >> some
    > >> unsigned integer types are still missing. (Under Windows e.g.,
    > >> there is more than one 32-bit unsigned integer type.)
    > >> Types like size_t and clock_t map to different types on different
    > >> platforms.
    > >> I wonder whether it is possible to create a complete list,
    > >> without using conditional code selection in the preprocessor.
    > >> Is the list "unsigned char, unsigned short, unsigned int, unsigned
    > >> long and unsigned long long" complete and without overlap (as far as
    > >> specializations concern) for all platforms?
    > >> Should I add unsigned wchar_t, or is it covered already?

    >
    > >> (I know that char needs special attention. I know how to handle that
    > >> case.)

    >
    > > Your list seems exhaustive, and "unsigned wchar_t" should be already
    > > covered by your list (after all, it should be just an unsigned integer
    > > somewhat bigger than char). But you'll eventually get more certain
    > > answers about this.

    >
    > > About avoiding to create all those specializations, can you get along
    > > with duplicating the body of your template to include both algorithms,
    > > checking then for unsigned-ness at runtime via numeric_limits?

    >
    > > The compiler could then optimize away the algorithm version that
    > > doesn't happen to be appropriate for each type - at least, I suppose
    > > so, I'd have to check if it works but I'm not so sure I will able to.

    >
    > > Just an idea off the top of my head.

    >
    > Thanks for the suggestion. I tried something along these lines.
    > It compiles and works as expected, but some compilers generate a lot
    > of warnings for those lines where tests are made for the sign of the
    > values during instantiations of unsigned types. Since this header is
    > included in may modules, I get many warnings which I cannot suppress
    > and which makes it difficult to find the more relevant warnings.


    I didn't think about those warnings.

    Just in case: once you're assured that unsigned types will never make
    it in your signed algo, couldn't you throw away those tests for
    negativeness in the signed algo? Or perhaps change them so that they
    don't raise warnings, if they're really needed.

    For example, a check for some value being not negative can be
    expressed as:
    -------
    if(val > -1) { /*...*/ };
    -------

    But also as either:
    -------
    if(val >= 0) { /* ... */ };
    if(!(val < 0)) { /* ... */ };
    -------

    The latter two shouldn't raise any warning even if applied to unsigned
    types, mmm, no, the compiler will eventually warn that those tests
    always evaluate "true"...

    Maybe the only way to avoid those warnings and taking advantage of the
    templates is wrapping those algos within template classes, but as you
    have already noted with Kai-Uwe, this is going to increase complexity
    - and notation, too, I suspect.

    Wait: what about this:
    -------
    if(val == 0 || val > 0) { /* ... */ };
    -------

    The above should issue no warning at all! Am I correct?
    Compilers cannot be _that_ clever, can they?

    Ahh. If you happen to find a compiler that warns on the above, try
    this:
    -------
    T zero = 0; /* note: non-const... could a "volatile" help too, here?
    */
    if(val >= zero) { /* ... */ };
    -------

    Anyway, gcc 3.4.5 never warned me for "always true/false" conditionals
    - with "-Wall -pedantic" would them have been needed.

    To avoid the weird part of my suggestion (duplicating the code in the
    template body) one could make two different templates and wrap the
    decision in a third one:
    -------
    #include <limits>

    template<class T> void signed_algo(const T& one, const T& two) {
    // ...
    }

    template<class T> void unsigned_algo(const T& one, const T& two) {
    // ...
    }

    template<class T> void algo(const T& one, const T& two) {
    if(std::numeric_limits<T>::is_signed) {
    signed_algo(one, two);
    } else {
    unsigned_algo(one, two);
    }
    }
    -------

    Well, you surely have considered all of this already, I'm posting it
    just for the occasional reader.

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 13, 2009
    #8
  9. Fred Zwarts

    James Kanze Guest

    On Oct 13, 12:31 pm, "Fred Zwarts" <> wrote:
    > Kai-Uwe Bux wrote:
    > > Fred Zwarts wrote:


    > >> I have created a template function for a generic algorithm. For
    > >> unsigned integer types, a small modification in the algorithm is
    > >> needed, because I can't use negative values there. So, I want to
    > >> make specializations for all unsigned integer types.


    > > Maybe the following helps:


    > > template < typename T >
    > > struct is_signed {
    > > static bool const value = 0 > T(-1);
    > > };


    > >> I assume that it is not possible in C++ to write one specialization
    > >> for all unsigned integer type, but that a specialization for each
    > >> unsigned integer type must be created.


    > > No, but you could do:


    > > template < typename T, bool IsSigned = is_signed<T>::value >
    > > struct ...


    > > and partially specialize that for <T,true> and <T,false>.


    > > [...]


    > I tried something along these lines, but it turned out to my surprise,
    > that partial specializations are not allowed for template functions,
    > only for template classes/structs. Of course I could encapsulate the
    > function in a class and add a wrapper function...


    Or you could forward to an overloaded function, something like:

    template< bool > class Discrim {};

    template< typename T >
    void helper( T value, Discrim< false > )
    {
    // signed...
    }

    template< typename T >
    void helper( T value, Discrim< true > )
    {
    // unsigned...
    }

    template< typename T >
    void function( T value )
    {
    helper( value, Discrim< is_signed< T >::value >() ) ;
    }

    If you're doing a lot of this (or even more than once), you'll have
    Discrim already written, and maybe even is_signed, so all that's left
    is
    the two overloads. (I don't claim that this is a better or a worse
    solution than the partial specializations suggested by Kai-Uwe---I
    generally use his method myself. But it's an alternative you might
    consider.)

    --
    James Kanze
     
    James Kanze, Oct 13, 2009
    #9
  10. Fred Zwarts

    James Kanze Guest

    On Oct 13, 12:37 pm, Kai-Uwe Bux <> wrote:
    > Fred Zwarts wrote:
    > > Kai-Uwe Bux wrote:

    > [...]
    > >> No, but you could do:


    > >> template < typename T, bool IsSigned = is_signed<T>::value >
    > >> struct ...


    > >> and partially specialize that for <T,true> and <T,false>.


    > >> [...]


    > > I tried something along these lines, but it turned out to my
    > > surprise, that partial specializations are not allowed for template
    > > functions, only for template classes/structs. Of course I could
    > > encapsulate the function in a class and add a wrapper function...


    > Yup. That is annoying. Maybe the most prominent case is specializing a
    > generic algorithm to take advantage of random access iterators. You
    > have to wrap the algorithm as a static member function of a class
    > template, which you can specialize in turn.


    Why don't you do like is done in most of the standard libraries:
    overload the function with an additional argument:

    template< typename RandomIterator >
    void f( RandomIterator begin,
    RandomIterator end,
    std::random_access_iterator_tag )
    {
    }

    template< typename OtherIterator >
    void f( OtherIterator begin,
    OtherIterator end,
    std::input_iterator_tag )
    {
    }

    template< typename Iterator >
    void f( Iterator begin, Iterator end )
    {
    f( begin, end,
    typename std::iterator_traits< Iterator
    >::iterator_category() );

    }

    (I'm not sure that it's really that much simpler, but it is what I've
    seen in the standard library. Note too that it does take advantage of
    the inheritance in the iterator tags, so that a forward iterator will
    automatically end up in the second overload, without having to
    explicitly provide for it.)

    --
    James Kanze
     
    James Kanze, Oct 13, 2009
    #10
  11. Fred Zwarts

    James Kanze Guest

    On Oct 13, 10:50 pm, Sam <> wrote:
    > Kai-Uwe Bux writes:
    > > Fred Zwarts wrote:


    > >> I have created a template function for a generic algorithm.
    > >> For unsigned integer types, a small modification in the
    > >> algorithm is needed, because I can't use negative values
    > >> there. So, I want to make specializations for all unsigned
    > >> integer types.


    > > Maybe the following helps:


    > > template < typename T >
    > > struct is_signed {
    > > static bool const value = 0 > T(-1);
    > > };


    > Are there any particular advantages to this reinvention of the
    > std::numeric_limits<ClassT>::is_signed wheel?


    Technically, the only instantiations of numeric_limits that are
    required are those for the standard numeric types; there's no
    guarantee that e.g. numeric_limits< uptrint_t > or
    numeric_limits< UserDefinedInt > exist. From a QoI point of
    view, I would certainly expect the first; as to the second, a
    well written library will provide it, but it's the sort of thing
    I'd be hesitant about counting on.

    --
    James Kanze
     
    James Kanze, Oct 14, 2009
    #11
  12. Fred Zwarts

    Kai-Uwe Bux Guest

    James Kanze wrote:

    > On Oct 13, 12:37 pm, Kai-Uwe Bux <> wrote:
    >> Fred Zwarts wrote:
    >> > Kai-Uwe Bux wrote:

    >> [...]
    >> >> No, but you could do:

    >
    >> >> template < typename T, bool IsSigned = is_signed<T>::value >
    >> >> struct ...

    >
    >> >> and partially specialize that for <T,true> and <T,false>.

    >
    >> >> [...]

    >
    >> > I tried something along these lines, but it turned out to my
    >> > surprise, that partial specializations are not allowed for template
    >> > functions, only for template classes/structs. Of course I could
    >> > encapsulate the function in a class and add a wrapper function...

    >
    >> Yup. That is annoying. Maybe the most prominent case is specializing a
    >> generic algorithm to take advantage of random access iterators. You
    >> have to wrap the algorithm as a static member function of a class
    >> template, which you can specialize in turn.

    >
    > Why don't you do like is done in most of the standard libraries:
    > overload the function with an additional argument:
    >
    > template< typename RandomIterator >
    > void f( RandomIterator begin,
    > RandomIterator end,
    > std::random_access_iterator_tag )
    > {
    > }
    >
    > template< typename OtherIterator >
    > void f( OtherIterator begin,
    > OtherIterator end,
    > std::input_iterator_tag )
    > {
    > }
    >
    > template< typename Iterator >
    > void f( Iterator begin, Iterator end )
    > {
    > f( begin, end,
    > typename std::iterator_traits< Iterator
    >>::iterator_category() );

    > }
    >
    > (I'm not sure that it's really that much simpler, but it is what I've
    > seen in the standard library. Note too that it does take advantage of
    > the inheritance in the iterator tags, so that a forward iterator will
    > automatically end up in the second overload, without having to
    > explicitly provide for it.)


    That's cute. I had not thaught of that.


    Thanks

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Oct 14, 2009
    #12
  13. Fred Zwarts

    James Kanze Guest

    On Oct 14, 12:08 pm, Sam <> wrote:
    > James Kanze writes:
    > > On Oct 13, 10:50 pm, Sam <> wrote:
    > >> Kai-Uwe Bux writes:
    > >> > Fred Zwarts wrote:


    > >> >> I have created a template function for a generic algorithm.
    > >> >> For unsigned integer types, a small modification in the
    > >> >> algorithm is needed, because I can't use negative values
    > >> >> there. So, I want to make specializations for all unsigned
    > >> >> integer types.


    > >> > Maybe the following helps:


    > >> > template < typename T >
    > >> > struct is_signed {
    > >> > static bool const value = 0 > T(-1);
    > >> > };


    > >> Are there any particular advantages to this reinvention of the
    > >> std::numeric_limits<ClassT>::is_signed wheel?


    > > Technically, the only instantiations of numeric_limits that are
    > > required are those for the standard numeric types; there's no
    > > guarantee that e.g. numeric_limits< uptrint_t > or
    > > numeric_limits< UserDefinedInt > exist. From a QoI point of


    > I would expect that any typedefs will get bound to the
    > underlying types:


    They will, but the underlying type may be an extended integral
    type, e.g.:
    typedef __uint64 uprtint_t;
    or something similar. As I said, in such cases, I would expect
    (from a QoI point of view) that the implementation also provide
    a specialization for the underlying type; I think the next
    version of the standard (which officializes such extended
    integral types) will require it. For the moment, however, we're
    in a sort of a transitional period, where it sometimes occurs
    that types are only partially supported---I've definitely used
    compilers where the compiler itself knew about long long, but it
    didn't work with anything in the library (including
    numeric_limits). It's an awkward situation, but it's one we
    have to live with at present.

    --
    James Kanze
     
    James Kanze, Oct 15, 2009
    #13
  14. James Kanze <> wrote:
    > On Oct 13, 12:31 pm, "Fred Zwarts" <> wrote:
    >
    >
    >
    > > Kai-Uwe Bux wrote:
    > > > Fred Zwarts wrote:
    > > >> I have created a template function for a generic algorithm.  For
    > > >> unsigned integer types, a small modification in the algorithm is
    > > >> needed, because I can't use negative values there.  So, I want to
    > > >> make specializations for all unsigned integer types.
    > > > Maybe the following helps:
    > > >  template < typename T >
    > > >  struct is_signed {
    > > >    static bool const value = 0 > T(-1);
    > > >  };
    > > >> I assume that it is not possible in C++ to write one specialization
    > > >> for all unsigned integer type, but that a specialization for each
    > > >> unsigned integer type must be created.
    > > > No, but you could do:
    > > >  template < typename T, bool IsSigned = is_signed<T>::value >
    > > >  struct ...
    > > > and partially specialize that for <T,true> and <T,false>.
    > > > [...]

    > > I tried something along these lines, but it turned out to my surprise,
    > > that partial specializations are not allowed for template functions,
    > > only for template classes/structs. Of course I could encapsulate the
    > > function in a class and add a wrapper function...

    >
    > Or you could forward to an overloaded function, something like:
    >
    >     template< bool > class Discrim {};
    >
    >     template< typename T >
    >     void helper( T value, Discrim< false > )
    >     {
    >         //  signed...
    >     }
    >
    >     template< typename T >
    >     void helper( T value, Discrim< true > )
    >     {
    >         //  unsigned...
    >     }
    >
    >     template< typename T >
    >     void function( T value )
    >     {
    >         helper( value, Discrim< is_signed< T >::value >() ) ;
    >     }
    >
    > If you're doing a lot of this (or even more than once), you'll have
    > Discrim already written, and maybe even is_signed, so all that's left
    > is
    > the two overloads.  (I don't claim that this is a better or a worse
    > solution than the partial specializations suggested by Kai-Uwe---I
    > generally use his method myself.  But it's an alternative you might
    > consider.)


    Really good to learn about these "tricks" - let's call them so - to
    overcome the lack of partial specialization for functions.

    Thanks to both James and Kai-Uwe.

    It's always instructive to read this NG.

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 15, 2009
    #14
  15. On 13/10/09 14:17, Francesco S. Carta wrote:

    []

    > To avoid the weird part of my suggestion (duplicating the code in the
    > template body) one could make two different templates and wrap the
    > decision in a third one:
    > -------
    > #include<limits>
    >
    > template<class T> void signed_algo(const T& one, const T& two) {
    > // ...
    > }
    >
    > template<class T> void unsigned_algo(const T& one, const T& two) {
    > // ...
    > }
    >
    > template<class T> void algo(const T& one, const T& two) {
    > if(std::numeric_limits<T>::is_signed) {
    > signed_algo(one, two);
    > } else {
    > unsigned_algo(one, two);
    > }
    > }
    > -------
    >
    > Well, you surely have considered all of this already, I'm posting it
    > just for the occasional reader.


    An occasional reader is here ;)

    Noticed that algo() uses a runtime if() statement which causes both
    signed_algo and unsigned_algo to be instantiated for every T. The
    optimizer will determine that std::numeric_limits<T>::is_signed is a
    compile-time constant and throw away the dead branch, but still both
    templates are instantiated.

    It is easy to eliminate the unnecessary instantiation and make the
    compiler instantiate only the template function which is actually called:

    #include <limits>

    template<bool> struct Bool {};
    typedef Bool<true> True;
    typedef Bool<false> False;

    template<class T>
    void algo(const T& one, const T& two, /*signed*/ True) {
    // ...
    }

    template<class T>
    void algo(const T& one, const T& two, /*signed*/ False) {
    // ...
    }

    template<class T> void algo(const T& one, const T& two) {
    algo(one, two, Bool<std::numeric_limits<T>::is_signed>());
    }

    int main()
    {
    algo(1, 1);
    algo(1u, 1u);
    }

    --
    Max
     
    Maxim Yegorushkin, Oct 17, 2009
    #15
  16. Maxim Yegorushkin <> wrote:
    > On 13/10/09 14:17, Francesco S. Carta wrote:
    >
    > []
    >
    >
    >
    > > To avoid the weird part of my suggestion (duplicating the code in the
    > > template body) one could make two different templates and wrap the
    > > decision in a third one:
    > > -------
    > > #include<limits>

    >
    > > template<class T>  void signed_algo(const T&  one, const T&  two) {
    > >      // ...
    > > }

    >
    > > template<class T>  void unsigned_algo(const T&  one, const T&  two) {
    > >      // ...
    > > }

    >
    > > template<class T>  void algo(const T&  one, const T&  two) {
    > >      if(std::numeric_limits<T>::is_signed) {
    > >          signed_algo(one, two);
    > >      } else {
    > >          unsigned_algo(one, two);
    > >      }
    > > }
    > > -------

    >
    > > Well, you surely have considered all of this already, I'm posting it
    > > just for the occasional reader.

    >
    > An occasional reader is here ;)
    >
    > Noticed that algo() uses a runtime if() statement which causes both
    > signed_algo and unsigned_algo to be instantiated for every T. The
    > optimizer will determine that std::numeric_limits<T>::is_signed is a
    > compile-time constant and throw away the dead branch, but still both
    > templates are instantiated.
    >
    > It is easy to eliminate the unnecessary instantiation and make the
    > compiler instantiate only the template function which is actually called:
    >
    >      #include <limits>
    >
    >      template<bool> struct Bool {};
    >      typedef Bool<true> True;
    >      typedef Bool<false> False;
    >
    >      template<class T>
    >      void algo(const T& one, const T& two, /*signed*/ True) {
    >          // ...
    >      }
    >
    >      template<class T>
    >      void algo(const T& one, const T& two, /*signed*/ False) {
    >          // ...
    >      }
    >
    >      template<class T> void algo(const T& one, const T& two) {
    >          algo(one, two, Bool<std::numeric_limits<T>::is_signed>());
    >      }
    >
    >      int main()
    >      {
    >          algo(1, 1);
    >          algo(1u, 1u);
    >      }
    >


    Very good, but no cigar.

    Some days ago, James Kanze posted an equivalent snippet (your Bool<>
    == his Discrim<>).

    Sorry, the "no cigar" sentence has made my horror & delight so many
    times that I _had_ to use it at least once...

    Of course, I wasn't able to work out that solution by myself: one
    cigar each ;-)

    --
    Francesco S. Carta, http://fscode.altervista.org
     
    Francesco S. Carta, Oct 17, 2009
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eli Bendersky
    Replies:
    1
    Views:
    1,180
    Mike Treseler
    Mar 1, 2006
  2. Replies:
    14
    Views:
    2,143
    CBFalconer
    Jun 18, 2005
  3. Replies:
    163
    Views:
    3,315
  4. Replies:
    3
    Views:
    380
  5. pozz
    Replies:
    12
    Views:
    760
    Tim Rentsch
    Mar 20, 2011
Loading...

Share This Page