gecko/mfbt/TypeTraits.h
2012-10-22 17:05:07 -04:00

177 lines
4.2 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Template-based metaprogramming and type-testing facilities. */
#ifndef mozilla_TypeTraits_h_
#define mozilla_TypeTraits_h_
namespace mozilla {
namespace detail {
/**
* The trickery used to implement IsBaseOf here makes it possible to use it for
* the cases of private and multiple inheritance. This code was inspired by the
* sample code here:
*
* http://stackoverflow.com/questions/2910979/how-is-base-of-works
*/
template<class Base, class Derived>
class IsBaseOfHelper
{
public:
operator Base*() const;
operator Derived*();
};
} /* namespace detail */
/*
* IsBaseOf allows to know whether a given class is derived from another.
*
* Consider the following class definitions:
*
* class A {};
* class B : public A {};
* class C {};
*
* mozilla::IsBaseOf<A, B>::value is true;
* mozilla::IsBaseOf<A, C>::value is false;
*/
template<class Base, class Derived>
class IsBaseOf
{
private:
template<class T>
static char test(Derived*, T);
static int test(Base*, int);
public:
static const bool value =
sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
};
template<class Base, class Derived>
class IsBaseOf<Base, const Derived>
{
private:
template<class T>
static char test(Derived*, T);
static int test(Base*, int);
public:
static const bool value =
sizeof(test(detail::IsBaseOfHelper<Base, Derived>(), int())) == sizeof(char);
};
template<class Base, class Derived>
class IsBaseOf<Base&, Derived&>
{
public:
static const bool value = false;
};
template<class Type>
class IsBaseOf<Type, Type>
{
public:
static const bool value = true;
};
template<class Type>
class IsBaseOf<Type, const Type>
{
public:
static const bool value = true;
};
/*
* IsConvertible determines whether a value of type From will implicitly convert
* to a value of type To. For example:
*
* struct A {};
* struct B : public A {};
* struct C {};
*
* mozilla::IsConvertible<A, A>::value is true;
* mozilla::IsConvertible<A*, A*>::value is true;
* mozilla::IsConvertible<B, A>::value is true;
* mozilla::IsConvertible<B*, A*>::value is true;
* mozilla::IsConvertible<C, A>::value is false;
* mozilla::IsConvertible<A, C>::value is false;
* mozilla::IsConvertible<A*, C*>::value is false;
* mozilla::IsConvertible<C*, A*>::value is false.
*
* For obscure reasons, you can't use IsConvertible when the types being tested
* are related through private inheritance, and you'll get a compile error if
* you try. Just don't do it!
*/
template<typename From, typename To>
struct IsConvertible
{
private:
static From create();
template<typename From1, typename To1>
static char test(To to);
template<typename From1, typename To1>
static int test(...);
public:
static const bool value =
sizeof(test<From, To>(create())) == sizeof(char);
};
/*
* Conditional selects a class between two, depending on a given boolean value.
*
* mozilla::Conditional<true, A, B>::Type is A;
* mozilla::Conditional<false, A, B>::Type is B;
*/
template<bool condition, class A, class B>
struct Conditional
{
typedef A Type;
};
template<class A, class B>
struct Conditional<false, A, B>
{
typedef B Type;
};
/*
* EnableIf is a struct containing a typedef of T if and only if B is true.
*
* mozilla::EnableIf<true, int>::Type is int;
* mozilla::EnableIf<false, int>::Type is a compile-time error.
*
* Use this template to implement SFINAE-style (Substitution Failure Is not An
* Error) requirements. For example, you might use it to impose a restriction
* on a template parameter:
*
* template<typename T>
* class PodVector // vector optimized to store POD (memcpy-able) types
* {
* EnableIf<IsPodType<T>, T>::Type* vector;
* size_t length;
* ...
* };
*/
template<bool B, typename T = void>
struct EnableIf
{};
template<typename T>
struct EnableIf<true, T>
{
typedef T Type;
};
} /* namespace mozilla */
#endif /* mozilla_TypeTraits_h_ */