Question

I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:

template <typename T>
class FXP<T>
{ ... };

template <typename T>
class FXP<unsigned T>
{ ... };

but this does not compile.

I even came across:

std::is_integral

std::is_signed
std::is_unsigned

So, how do I put these in action to define a class that only supports these two variants?

Was it helpful?

Solution

In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:

// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
     // default implementation here
};

Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).

template <typename T>
class FXP<T, false> {
     // partial specialization when is_unsigned becomes false
};

template <typename T>
class FXP<T, true> {
     // partial specialization when is_unsigned becomes true
};

In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).

Here's an example, where the default case gets overridden by a specialized template parameter: http://coliru.stacked-crooked.com/a/bc761b7b44b0d452

Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).

Good luck!

OTHER TIPS

With an additional template parameter:

#include <iostream>
#include <type_traits>

template <typename T, class X = void>
struct FXP
{
    // possibly disallow using this primary template:
    // static_assert(not std::is_same<X, X>{},
    //               "Error: type neither signed nor unsigned");
    void print() { std::cout << "non-specialized\n"; }
};

template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{  void print() { std::cout << "signed\n"; }  };

template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{  void print() { std::cout << "unsigned\n"; }  };

struct foo {};

int main()
{
    FXP<foo>().print();
    FXP<int>().print();
    FXP<unsigned int>().print();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top