@@ -31,32 +31,35 @@ | |||||
//! @{ | //! @{ | ||||
namespace utl { | namespace utl { | ||||
//! if_ | |||||
//! select _T1 or _T2 based on _C | |||||
//! @{ | //! @{ | ||||
template <bool _C, typename _T1, typename _T2> | template <bool _C, typename _T1, typename _T2> | ||||
struct if_ { | |||||
struct select_ { | |||||
typedef _T1 type; | typedef _T1 type; | ||||
}; | }; | ||||
template <typename _T1, typename _T2> | template <typename _T1, typename _T2> | ||||
struct if_ <false, _T1, _T2> { | |||||
struct select_ <false, _T1, _T2> { | |||||
typedef _T2 type; | typedef _T2 type; | ||||
}; | }; | ||||
//! @} | //! @} | ||||
//! enable_if | |||||
//! select _Tp if _C is true, else SFINAE | |||||
//! @{ | //! @{ | ||||
template <bool, typename _Tp = void> | |||||
struct enable_if { }; | |||||
// Partial specialization for true. | |||||
template<typename _Tp> | |||||
struct enable_if <true, _Tp> { | |||||
template <bool _C, typename _Tp = void> | |||||
struct if_ { | |||||
typedef _Tp type; | typedef _Tp type; | ||||
}; | }; | ||||
//! Alias template for enable_if | |||||
template<typename _Tp> // Partial specialization for false. | |||||
struct if_ <false, _Tp> { }; | |||||
//! Alias template for if_ | |||||
template<bool _C, typename _Tp = void> | |||||
using if_t = typename if_<_C, _Tp>::type; | |||||
//! Publicly recognized alias template for if_ | |||||
template<bool _C, typename _Tp = void> | template<bool _C, typename _Tp = void> | ||||
using enable_if_t = typename enable_if<_C, _Tp>::type; | |||||
using enable_if_t = typename if_<_C, _Tp>::type; | |||||
//! @} | //! @} | ||||
} | } | ||||
@@ -50,11 +50,11 @@ namespace utl { | |||||
template<typename _T1, typename _T2> | template<typename _T1, typename _T2> | ||||
struct or_ <_T1, _T2> | struct or_ <_T1, _T2> | ||||
: if_<_T1::value, _T1, _T2>::type { }; | |||||
: select_<_T1::value, _T1, _T2> { }; | |||||
template<typename _T1, typename _T2, typename _T3, typename... _Tn> | template<typename _T1, typename _T2, typename _T3, typename... _Tn> | ||||
struct or_<_T1, _T2, _T3, _Tn...> | struct or_<_T1, _T2, _T3, _Tn...> | ||||
: if_<_T1::value, _T1, or_<_T2, _T3, _Tn...>>::type { }; | |||||
: select_<_T1::value, _T1, or_<_T2, _T3, _Tn...>> { }; | |||||
//! @} | //! @} | ||||
//! AND implementation | //! AND implementation | ||||
@@ -71,11 +71,11 @@ namespace utl { | |||||
template<typename _T1, typename _T2> | template<typename _T1, typename _T2> | ||||
struct and_<_T1, _T2> | struct and_<_T1, _T2> | ||||
: if_<_T1::value, _T2, _T1>::type { }; | |||||
: select_<_T1::value, _T2, _T1> { }; | |||||
template<typename _T1, typename _T2, typename _T3, typename... _Tn> | template<typename _T1, typename _T2, typename _T3, typename... _Tn> | ||||
struct and_<_T1, _T2, _T3, _Tn...> | struct and_<_T1, _T2, _T3, _Tn...> | ||||
: if_<_T1::value, and_<_T2, _T3, _Tn...>, _T1>::type { }; | |||||
: select_<_T1::value, and_<_T2, _T3, _Tn...>, _T1> { }; | |||||
//! @} | //! @} | ||||
//! same | //! same | ||||
@@ -32,32 +32,83 @@ | |||||
//! @{ | //! @{ | ||||
namespace utl { | namespace utl { | ||||
//! If same type resolves to _Ret, else to SFINAE | |||||
/*! | |||||
* void_t | |||||
* Utility meta-function that maps a sequence of any types to the type void | |||||
* \note The idea is: | |||||
* template <typename ...> | |||||
* using void_t = void; | |||||
* | |||||
* Until CWG 1558 (a C++14 defect), unused parameters in alias templates were not | |||||
* guaranteed to ensure SFINAE and could be ignored, so earlier compilers require | |||||
* a more complex definition of void_t, such as the following implementation | |||||
* https://en.cppreference.com | |||||
*/ | |||||
//! @{ | //! @{ | ||||
template <typename _Tp1, typename _Tp2, typename _Ret> | |||||
template<typename... _Ts> | |||||
struct void_t_impl { | |||||
typedef void type; | |||||
}; | |||||
//! The actual void_t type alias | |||||
template<typename... _Ts> | |||||
using void_t = typename void_t_impl<_Ts...>::type; | |||||
//! @} | |||||
//! If same type resolves to _Ret, else SFINAE | |||||
//! @{ | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
struct use_if_same_ { | struct use_if_same_ { | ||||
using type = enable_if_t < | |||||
same_<_Tp1, _Tp2>::value, | |||||
using type = if_t < | |||||
same_<_T1, _T2>::value, | |||||
_Ret | _Ret | ||||
>; | >; | ||||
}; | }; | ||||
template <typename _Tp1, typename _Tp2, typename _Ret> | |||||
using use_if_same_t = typename use_if_same_<_Tp1, _Tp2, _Ret>::type; | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
using use_if_same_t = typename use_if_same_<_T1, _T2, _Ret>::type; | |||||
//! @} | //! @} | ||||
//! If same type resolves to SFINAE, else to _Ret | |||||
//! If not same type resolves to _Ret, else SFINAE | |||||
//! @{ | //! @{ | ||||
template <typename _Tp1, typename _Tp2, typename _Ret> | |||||
struct discard_if_same_ { | |||||
using type = enable_if_t < | |||||
!same_<_Tp1, _Tp2>::value, | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
struct use_if_not_same_ { | |||||
using type = if_t < | |||||
!same_<_T1, _T2>::value, | |||||
_Ret | _Ret | ||||
>; | >; | ||||
}; | }; | ||||
template <typename _Tp1, typename _Tp2, typename _Ret> | |||||
using discard_if_same_t = typename discard_if_same_<_Tp1, _Tp2, _Ret>::type; | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
using use_if_not_same_t = typename use_if_not_same_<_T1, _T2, _Ret>::type; | |||||
//! @} | //! @} | ||||
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE | |||||
//! @{ | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
struct use_if_any_ { | |||||
using type = if_t < | |||||
or_<_T1, _T2>::value, | |||||
_Ret | |||||
>; | |||||
}; | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
using use_if_any_t = typename use_if_any_<_T1, _T2, _Ret>::type; | |||||
//! @} | |||||
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE | |||||
//! @{ | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
struct use_if_both_ { | |||||
using type = if_t < | |||||
and_<_T1, _T2>::value, | |||||
_Ret | |||||
>; | |||||
}; | |||||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||||
using use_if_both_t = typename use_if_both_<_T1, _T2, _Ret>::type; | |||||
//! @} | |||||
} | } | ||||
//! @} | //! @} | ||||
@@ -1,52 +0,0 @@ | |||||
/*! | |||||
* \file void_t.h | |||||
* \brief Template meta-programming helpers | |||||
* | |||||
* Copyright (C) 2018 Christos Choutouridis | |||||
* | |||||
* This program is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU Lesser General Public License as | |||||
* published by the Free Software Foundation, either version 3 | |||||
* of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef __utl_meta_void_t_h__ | |||||
#define __utl_meta_void_t_h__ | |||||
#include <utl/impl/version.h> | |||||
//! \ingroup meta | |||||
//! \defgroup void_t | |||||
//! A void_t implementation for utl | |||||
//! @{ | |||||
namespace utl { | |||||
/*! | |||||
* Utility meta-function that maps a sequence of any types to the type void | |||||
* \note The idea is: | |||||
* template <typename ...> | |||||
* using void_t = void; | |||||
* | |||||
* Until CWG 1558 (a C++14 defect), unused parameters in alias templates were not | |||||
* guaranteed to ensure SFINAE and could be ignored, so earlier compilers require | |||||
* a more complex definition of void_t, such as the following implementation | |||||
* https://en.cppreference.com | |||||
*/ | |||||
template<typename... _Ts> | |||||
struct void_impl { | |||||
typedef void type; | |||||
}; | |||||
//! The actual void_t type alias | |||||
template<typename... _Ts> | |||||
using void_t = typename void_impl<_Ts...>::type; | |||||
} | |||||
//! @} | |||||
#endif /* __utl_meta_void_t_h__ */ |