• Forum
  • Lounge
  • LImiting Templates to particular types w

 
LImiting Templates to particular types with traits and static_assert

I managed to figure out how to do this, so am posting here in case it is of use to someone.

My goal was to make a template for Circles, that could be restricted in the types it could have. Obviously a Circle with radius 'z' doesn't make much sense.

static_assert produces a compile time error, which is ideally where we want to catch problems. The traits produce a boolean value for various tests including types. Curiously, not for char though !? So I adapted some code found at cppreference here is the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef CCIRCLE_H
#define CCIRCLE_H

#include <iostream>
#include <type_traits>

template< typename C >
struct is_char : std::integral_constant<bool,
                     std::is_same<C, char>::value      ||
                     std::is_same<C,  char16_t>::value ||
                     std::is_same<C, char32_t>::value  ||
                     std::is_same<C,  wchar_t>::value>
                     {};

template<typename T >
class CCircle {
public:
   CCircle(T radius) {
      static_assert(std::is_arithmetic<T>::value, "T must be of Numeric type");
      //static_assert(!std::is_same<T, char>::value, "Type cannot be char");
      static_assert(!is_char<T>::value, "is char Type cannot be char");

      m_Radius = radius;
   }

   void Print() {
      std::cout << m_Radius << "\n";
   }

private:
   T m_Radius;
};
#endif // CCIRCLE_H 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include "CCircle.h"

int main()
{
   
   CCircle<int> a(10);
   CCircle<float> b(20.0f);
   CCircle<double> c(30.0);
   CCircle<char> d('z'); // Produces compile error


   a.Print();
   b.Print();
   c.Print();
   d.Print();

   return 0;
}


The is_same trait is very handy for comparing to one of your own classes. I could use this to make sure a typename U (a centre point) is a class CPoint2D say.

Further uses would be to make integral types unsigned, and call std::abs if a FP type value is negative.

One downside might be that initialisation is happening by assignment, rather than by initialisation list, but I think it would be OK in a Validation class rather than a Data class.

http://en.cppreference.com/w/cpp/types
http://en.cppreference.com/w/cpp/types/is_arithmetic
One downside might be that initialisation is happening by assignment, rather than by initialisation list,

No reason not to

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T >
class CCircle {
public:
  static_assert(std::is_arithmetic<T>::value
                && !is_char<T>::value, "Type must be arithmetic, but not char");

   CCircle(T radius) : m_Radius(radius) {}

   void Print() const {
      std::cout << m_Radius << "\n";
   }

private:
   T m_Radius;
};
Last edited on
Cheers Cubbi, awesome as per usual! :+D.

Topic archived. No new replies allowed.