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:
Fischlurch 2016-01-05 20:53:31 +01:00
parent ff7ac5523f
commit c104e28ebf
5 changed files with 94 additions and 71 deletions

View file

@ -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

View file

@ -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.

View file

@ -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>;

View file

@ -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;

View file

@ -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;