Blob Blame Raw
#pragma once

#ifndef TCG_SFINAE_H
#define TCG_SFINAE_H

/*!
  \file     sfinae.h

  \brief    Contains template metafunctions that can be used to enable or
            disable template class members.

  \details  SFINAE (Substitution Failure Is Not An Error) is a C++ \a feature
            that allows the compiler to silently discard failures in template
            function instantiations during function overload resolution.
*/

#if defined(__APPLE_CC__)
#include <type_traits>
#endif

namespace tcg {

template <typename X, typename Y>
struct type_match {
  enum { value = false };
};

template <typename X>
struct type_match<X, X> {
  enum { value = true };
};

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

template <typename X, typename Y>
struct type_mismatch {
  enum { value = true };
};

template <typename X>
struct type_mismatch<X, X> {
  enum { value = false };
};

//========================================================================

template <typename T, typename B>
struct enable_if_exists {
  typedef B type;
};

//========================================================================

template <bool, typename T = void>
struct enable_if {};

template <typename T>
struct enable_if<true, T> {
  typedef T type;
};

//========================================================================

template <bool, typename T = void>
struct disable_if {
  typedef T type;
};

template <typename T>
struct disable_if<true, T> {};

//========================================================================

template <bool, typename TrueT, typename FalseT = void>
struct choose_if;

template <typename TrueT, typename FalseT>
struct choose_if<true, TrueT, FalseT> {
  typedef TrueT type;
};

template <typename TrueT, typename FalseT>
struct choose_if<false, TrueT, FalseT> {
  typedef FalseT type;
};

//========================================================================

template <typename T, typename MatchT, typename NotMatchedT = void>
struct choose_if_match {
  typedef NotMatchedT type;
};

template <typename MatchT, typename NotMatchedT>
struct choose_if_match<MatchT, MatchT, NotMatchedT> {
  typedef MatchT type;
};

}  // namespace tcg

#endif  // TCG_SFINAE_H