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.