11

Briefly dismiss the fact that normal function overloading will serve this example better. It is meant only as a way to learn about template programming. Having said that, you are welcome to comment on the benefits/differences you'll get from using function overload, compared to function template specialization (although that might deserve a question of its own).


Consider the following example:

template <typename T>
inline void ToString(T value, char* target, size_t max_size );

template <>
inline void ToString<float>(float value, char* target, size_t max_size)
{
   snprintf( target , max_size , "%f" , value);
}

template <>
inline void ToString<double>(double value, char* target, size_t max_size)
{
    snprintf( target , max_size , "%f" , value);
}

Is there a way to write only one of these specializations that match both float and double types?

Basically I envision writing a template specialization for a template type that will match both float and double (as sort of 'float or double' type matcher) but I'm not sure whether that is possible at all with C++. That said, I've seen unexpected template magic happen in front of my eyes before, so I think it's a good question to ask here.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
lurscher
  • 25,930
  • 29
  • 122
  • 185
  • 1
    If you want something that matches more than one concrete type, then that's partial specialization, which isn't allowed for functions. – Kerrek SB Sep 02 '11 at 15:52
  • hi @Kerrek, my understanding of partial specialization is that is about specializing a subset of the template parameters. I only have one template parameter in here. I don't follow how partial specialization is relevant here – lurscher Sep 02 '11 at 15:54
  • 2
    Partial specialization means that the result is still a template, rather than a type. Consider for example `template struct X; template struct X;` That's partial. – Kerrek SB Sep 02 '11 at 15:57
  • @Kerrek, how would you do it using a function object template? – lurscher Sep 02 '11 at 16:06
  • Wrap the thing into a class, and specialize to heart's content. – Kerrek SB Sep 02 '11 at 16:06
  • @Kerrek, the part is not clear is what i should put in the specialization parameters. For your example on pointer types it would be T*, what would be in this case? – lurscher Sep 02 '11 at 16:10

1 Answers1

5

Here's a standard solution idiom:

#include <type_traits>
#include <cstdio>


// Helper class

template <typename T>
struct Printer
{
  static typename std::enable_if<std::is_floating_point<T>::value, int>::type
  print(T x, char * out, std::size_t n)
  {
    return std::snprintf(out, n, "%f", x);
  }
};

// Convenience function wrapper

template <typename T> int print(T x, char * out, std::size_t n)
{
  return Printer<T>::print(x, out, n);
}

void f()
{
  char a[10];

  Printer<double>::print(1.2, a, 10);  // use helper class
  print(1.4f, a, 10);                  // wrapper deduces type for you
}

You'll get a compile-time error if you call either construction with a non-floating type. Beware though that this might erroneously work for long doubles, which require the %Lf format specifier; and also recall that floats get promoted to doubles when passed through variadic function arguments.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084