inline(#985): provide our own minimal variant of enable_if
this is a stripped-down and very leightweight variant of the well-known enable_if metaprogramming trick. Providing this standard variant in a header with minimal dependencies will allow us to phase out boost inclusions from many further headers. As a plus, our own variant is written such as to be more conciese in usage (no "typename" and no acces of an embedded "::type" menber)
This commit is contained in:
parent
ff7ac5523f
commit
c104e28ebf
5 changed files with 94 additions and 71 deletions
|
|
@ -80,6 +80,7 @@ typedef unsigned int uint;
|
|||
|
||||
using lib::diff::GenNode;
|
||||
using lib::P;
|
||||
using lib::meta::enable_if;
|
||||
using lib::meta::can_convertToString;
|
||||
|
||||
using std::string;
|
||||
|
|
@ -90,22 +91,6 @@ using std::endl;
|
|||
|
||||
|
||||
|
||||
/////////////////////////////////////////planned for meta/util.hpp
|
||||
template <bool B, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enable_if_c<false, T> {};
|
||||
|
||||
template <class Cond, class T = void>
|
||||
using enable_if = typename enable_if_c<Cond::value, T>::type;
|
||||
|
||||
template <class Cond, class T = void>
|
||||
using disable_if = typename enable_if_c<not Cond::value, T>::type;
|
||||
|
||||
/////////////////////////////////////////planned for meta/util.hpp
|
||||
|
||||
|
||||
///////////////////////////////copied from format-util.hpp
|
||||
|
|
|
|||
|
|
@ -59,6 +59,43 @@ namespace std { // forward declaration for std::string...
|
|||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
/* === conditional definition selector === */
|
||||
|
||||
template <bool B, class T = void>
|
||||
struct enable_if_c {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct enable_if_c<false, T> {};
|
||||
|
||||
|
||||
/** SFINAE helper to control the visibility of specialisations and overloads.
|
||||
* \par explanation
|
||||
* This template needs to be interspersed somehow into a type expression, which
|
||||
* is driven by an external, primary type parameter. Thus, it is possible to use
|
||||
* it on an extraneous, possibly default template parameter, or when forming the
|
||||
* return type of a function. The purpose is to remove a given definition from
|
||||
* sight, unless a boolean condition `Cond::value` holds true. In the typical
|
||||
* usage, this condition is suppled by a _metafunction_, i.e. a template, which
|
||||
* detects some feature or other circumstantial condition with the types involved.
|
||||
* @remarks this is a widely used facility, available both from boost and from
|
||||
* the standard library. For the most common case, we roll our own
|
||||
* variant here, which is slightly stripped down and a tiny bit
|
||||
* more concise than the boost variant. This way, we can avoid
|
||||
* a lot of boost inclusions, which always bear some weight.
|
||||
* @see [std::enable_if](http://en.cppreference.com/w/cpp/types/enable_if)
|
||||
*/
|
||||
template <class Cond, class T = void>
|
||||
using enable_if = typename enable_if_c<Cond::value, T>::type;
|
||||
|
||||
template <class Cond, class T = void>
|
||||
using disable_if = typename enable_if_c<not Cond::value, T>::type;
|
||||
|
||||
|
||||
|
||||
|
||||
/* === building metafunctions === */
|
||||
|
||||
/** helper types to detect the overload resolution chosen by the compiler */
|
||||
|
||||
|
|
@ -68,7 +105,6 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
|
||||
/** detect possibility of a conversion to string.
|
||||
* Naive implementation just trying the direct conversion.
|
||||
* The embedded constant #value will be true in case this succeeds.
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ namespace meta{
|
|||
using std::is_move_constructible;
|
||||
using std::is_copy_constructible;
|
||||
using std::is_copy_assignable;
|
||||
using std::enable_if;
|
||||
using std::__and_;
|
||||
using std::__not_;
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
|
|
@ -239,44 +240,47 @@ namespace meta{
|
|||
|
||||
|
||||
|
||||
/** workaround for GCC 4.7: need to exclude some types,
|
||||
* since they raise private access violation during probing.
|
||||
* Actually, in C++11 such a case should trigger substitution
|
||||
* failure, not an compilation error */
|
||||
template<class X>
|
||||
struct can_use_assignment
|
||||
: is_copy_assignable<X>
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct can_use_assignment<lib::time::Time>
|
||||
{ static constexpr bool value = false; };
|
||||
|
||||
|
||||
|
||||
template<class X>
|
||||
struct use_if_supports_only_move
|
||||
: enable_if< is_move_constructible<X>::value
|
||||
&& !is_copy_constructible<X>::value
|
||||
&& !can_use_assignment<X>::value
|
||||
>
|
||||
{ };
|
||||
|
||||
template<class X>
|
||||
struct use_if_supports_cloning
|
||||
: enable_if< is_move_constructible<X>::value
|
||||
&& is_copy_constructible<X>::value
|
||||
&& !can_use_assignment<X>::value
|
||||
>
|
||||
{ };
|
||||
|
||||
template<class X>
|
||||
struct use_if_supports_copy_and_assignment
|
||||
: enable_if< is_move_constructible<X>::value
|
||||
&& is_copy_constructible<X>::value
|
||||
&& can_use_assignment<X>::value
|
||||
>
|
||||
{ };
|
||||
namespace { // helpers to select suitable variant of copy support...
|
||||
|
||||
/** workaround for GCC 4.7: need to exclude some types,
|
||||
* since they raise private access violation during probing.
|
||||
* Actually, in C++11 such a case should trigger substitution
|
||||
* failure, not an compilation error */
|
||||
template<class X>
|
||||
struct can_use_assignment
|
||||
: is_copy_assignable<X>
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct can_use_assignment<lib::time::Time>
|
||||
{ static constexpr bool value = false; };
|
||||
|
||||
|
||||
|
||||
template<class X>
|
||||
struct supports_only_move
|
||||
: __and_<is_move_constructible<X>
|
||||
,__not_<is_copy_constructible<X>>
|
||||
,__not_<can_use_assignment<X>>
|
||||
>
|
||||
{ };
|
||||
|
||||
template<class X>
|
||||
struct supports_cloning
|
||||
: __and_<is_move_constructible<X>
|
||||
,is_copy_constructible<X>
|
||||
,__not_<can_use_assignment<X>>
|
||||
>
|
||||
{ };
|
||||
|
||||
template<class X>
|
||||
struct supports_copy_and_assignment
|
||||
: __and_<is_move_constructible<X>
|
||||
,is_copy_constructible<X>
|
||||
,can_use_assignment<X>
|
||||
>
|
||||
{ };
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -292,21 +296,21 @@ namespace meta{
|
|||
};
|
||||
|
||||
template<class X>
|
||||
struct CopySupport<X, typename use_if_supports_only_move<X>::type>
|
||||
struct CopySupport<X, enable_if<supports_only_move<X>> >
|
||||
{
|
||||
template<class I, class D, class B =I>
|
||||
using Policy = MoveSupport<I,D,B>;
|
||||
};
|
||||
|
||||
template<class X>
|
||||
struct CopySupport<X, typename use_if_supports_cloning<X>::type>
|
||||
struct CopySupport<X, enable_if<supports_cloning<X>> >
|
||||
{
|
||||
template<class I, class D, class B =I>
|
||||
using Policy = CloneSupport<I,D,B>;
|
||||
};
|
||||
|
||||
template<class X>
|
||||
struct CopySupport<X, typename use_if_supports_copy_and_assignment<X>::type>
|
||||
struct CopySupport<X, enable_if<supports_copy_and_assignment<X>> >
|
||||
{
|
||||
template<class I, class D, class B =I>
|
||||
using Policy = FullCopySupport<I,D,B>;
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ namespace test {
|
|||
/* ===== printing Tuple types and contents ===== */
|
||||
|
||||
template<typename TYPES>
|
||||
typename enable_if< is_TuplePlain<Tuple<TYPES> >,
|
||||
string >::type
|
||||
enable_if< is_TuplePlain<Tuple<TYPES>>,
|
||||
string >
|
||||
showDump (Tuple<TYPES> const& tuple)
|
||||
{
|
||||
typedef BuildTupleAccessor<TYPES,TupleElementDisplayer> BuildAccessor;
|
||||
|
|
@ -150,8 +150,8 @@ namespace test {
|
|||
}
|
||||
|
||||
template<typename TYPES>
|
||||
typename enable_if< is_TupleListType<Tuple<TYPES> >,
|
||||
string >::type
|
||||
enable_if< is_TupleListType<Tuple<TYPES>>,
|
||||
string >
|
||||
showDump (Tuple<TYPES> const& tuple)
|
||||
{
|
||||
typedef typename Tuple<TYPES>::Type TypeSeq;
|
||||
|
|
@ -164,8 +164,8 @@ namespace test {
|
|||
}
|
||||
|
||||
template<typename TUP>
|
||||
typename enable_if< is_TuplePlain<TUP>,
|
||||
string >::type
|
||||
enable_if< is_TuplePlain<TUP>,
|
||||
string >
|
||||
showType ()
|
||||
{
|
||||
typedef InstantiateChained<typename TUP::ArgList, Printer, NullP> DumpPrinter;
|
||||
|
|
@ -174,8 +174,8 @@ namespace test {
|
|||
}
|
||||
|
||||
template<typename TUP>
|
||||
typename enable_if< is_TupleListType<TUP>,
|
||||
string >::type
|
||||
enable_if< is_TupleListType<TUP>,
|
||||
string >
|
||||
showType ()
|
||||
{
|
||||
typedef InstantiateChained<typename TUP::ArgList, Printer, NullP> DumpPrinter;
|
||||
|
|
|
|||
|
|
@ -44,12 +44,10 @@
|
|||
#include "lib/format-string.hpp"
|
||||
#include "lib/meta/util.hpp"
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
using std::string;
|
||||
using boost::enable_if;
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -187,8 +185,8 @@ namespace meta {
|
|||
/* ===== printing types and contents ===== */
|
||||
|
||||
template<typename TYPES>
|
||||
typename enable_if< is_Typelist<TYPES>,
|
||||
string >::type
|
||||
enable_if< is_Typelist<TYPES>,
|
||||
string >
|
||||
showType ()
|
||||
{
|
||||
typedef InstantiateChained<typename TYPES::List, Printer, NullP> DumpPrinter;
|
||||
|
|
|
|||
Loading…
Reference in a new issue