JPGygax68
11/16/2014 - 12:08 AM

How to implement custom traits (C++11)

How to implement custom traits (C++11)

#include <type_traits>
#include <iostream>

using std::enable_if;
using std::is_same;
using std::declval;
using std::integral_constant;

template <typename T>
using Invoke = typename T::type;

template <typename If, typename Then, typename Else>
using Conditional = Invoke<std::conditional<If::value, Then, Else>>;

template <typename... T>
struct All : std::true_type {};

template <typename Head, typename... Tail>
struct All<Head, Tail...> : Conditional<Head, All<Tail...>, std::false_type> {};
    
template <typename... Condition>
using EnableIf = typename std::enable_if<All<Condition...>::value>;
 
#define GPC_EXTEND_BOOL_TRAIT(name, ...) template <typename T> struct name<EnableIf<__VA_ARGS__>> : std::true_type {};

#define GPC_DEFINE_BOOL_TRAIT(name, ...) template <typename T> struct name: std::false_type {}; GPC_EXTEND_BOOL_TRAIT(name, __VA_ARGS__)


//--------------------------------------

// ok
//template <typename T>
//struct has_2d_coordinates: std::false_type {};

// ok
//template <typename T>
//struct has_2d_coordinates<std::enable_if<is_same<decltype(declval<T>().x), int>::value && is_same<decltype(declval<T>().y), int>::value>>: std::true_type {};

// ok
//template <typename T>
//struct has_2d_coordinates<std::enable_if<All<is_same<decltype(declval<T>().x), int>, is_same<decltype(declval<T>().y), int> >::value > >: std::true_type {};

// ok
//template <typename T> struct has_2d_coordinates< EnableIf< is_same<decltype(declval<T>().x), int>, is_same<decltype(declval<T>().y), int> >>: std::true_type {};


GPC_DEFINE_BOOL_TRAIT(has_2d_coordinates, is_same<decltype(declval<T>().x), int>, is_same<decltype(declval<T>().y), int>)

GPC_EXTEND_BOOL_TRAIT(has_2d_coordinates, is_same<decltype(declval<T>().x()), int>, is_same<decltype(declval<T>().y()), int>)

template <typename T>
void report(const char *name) {

    std::cout << name << " " << (has_2d_coordinates<T>::value ? "HAS 2D COORDINATES" : "DOESN'T have 2D coordinates") << std::endl;
}

#define REPORT(T) report<T>(#T)

int main() {

    struct EmptyStruct {};
    REPORT(EmptyStruct);
    
    struct Point { int x, y; };    
    REPORT(Point);

    struct BadPoint { int x_, y; };    
    REPORT(BadPoint);

    struct BadPoint2 { int x, y_; };    
    REPORT(BadPoint2);

    struct BadPoint3 { double x, y; };    
    REPORT(BadPoint3);
}