clean-up(#985): tighten basic header lib/meta/util.hpp

This header shall provide only very fundamental
metaprogramming helpers, since it is included pervasively
This commit is contained in:
Fischlurch 2016-01-05 20:10:20 +01:00
parent fec0a88753
commit ff7ac5523f
8 changed files with 109 additions and 87 deletions

View file

@ -38,14 +38,29 @@
#define LIB_META_UTIL_H
#include <string>
#include <typeinfo>
namespace std { // forward declaration for std::string...
template<typename C>
struct char_traits;
template<typename T>
class allocator;
template<typename c, class TRAIT, class _ALLO>
class basic_string;
using string = basic_string<char, char_traits<char>, allocator<char>>;
}
namespace lib {
namespace meta {
/* types for figuring out the overload resolution chosen by the compiler */
/** helper types to detect the overload resolution chosen by the compiler */
typedef char Yes_t;
struct No_t { char more_than_one[4]; };
@ -53,29 +68,12 @@ namespace meta {
/** Compile-time Type equality:
* Simple Trait template to pick up types considered
* \em identical by the compiler.
* @warning identical, not sub-type!
*/
template<typename T1, typename T2>
struct is_sameType
{
static const bool value = false;
};
template<typename T>
struct is_sameType<T,T>
{
static const bool value = true;
};
/** 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.
* Might fail in more tricky situations (references, const, volatile)
* @see \ref format-conv.hpp more elaborate solution including lexical_cast
* @see \ref format-obj.hpp more elaborate solution including lexical_cast
*/
template<typename T>
struct can_convertToString
@ -120,37 +118,6 @@ namespace meta {
/** semi-automatic detection if an instantiation is possible.
* Requires help by the template to be tested, which needs to define
* a typedef member \c is_defined. The embedded metafunction Test can be used
* as a predicate for filtering types which may yield a valid instantiation
* of the candidate template in question.
* @remarks
* A fully automated solution for this problem is impossible by theoretic reasons.
* Any non trivial use of such a \c is_defined trait would break the "One Definition Rule",
* as the state of any type can change from "partially defined" to "fully defined" over
* the course of any translation unit. Thus, even if there may be a \em solution out there,
* we can expect it to break at some point by improvements/fixes to the C++ Language.
*/
template<template<class> class _CandidateTemplate_>
struct Instantiation
{
template<class X>
class Test
{
typedef _CandidateTemplate_<X> Instance;
template<class U>
static Yes_t check(typename U::is_defined *);
template<class U>
static No_t check(...);
public:
static const bool value = (sizeof(Yes_t)==sizeof(check<Instance>(0)));
};
};
/** Trait template for detecting a typelist type.
* For example, this allows to write specialisations with the help of

View file

@ -32,11 +32,11 @@
** The header control-impl.hpp defines the building blocks for time::Control
** and then includes this header here to get the concrete template specialisations
** for time::mutation::Policy. This policy class is templated by time entity types
** - for \c TI, the \em nominal value type used on the time::Control interface
** - for \c SRC, the actual type of values to impose as \em change
** - for \c TI, the _nominal_ value type used on the time::Control interface
** - for \c SRC, the actual type of values to impose _as change_
** - for \c TAR, the target time value's type, receiving those changes.
**
** \par mutating a time value entity
** ## mutating a time value entity
**
** Actually imposing a change to the attached time value entity involves several
** steps. Each of these steps might be adapted specifically, in accordance to
@ -55,26 +55,26 @@
** point of the time interval given by the TimeSpan.
**
** Incoming changes might be of any of the aforementioned types, and in addition,
** we might receive \em nudging, which means to increment or decrement the target
** we might receive *nudging*, which means to increment or decrement the target
** time value in discrete steps. After maybe adapting these incoming change values,
** they may be actually \em imposed to the target. In all cases, this is delegated
** they may be actually _imposed_ on the target. In all cases, this is delegated
** to the time::Mutation base class, which is declared fried to TimeValue and thus
** has the exceptional ability to manipulate time values, which otherwise are defined
** to be immutable. Additionally, these protected functions in the time::Mutation
** baseclass also know how to handle \em nudge values, either by using the native
** baseclass also know how to handle _nudge values_, either by using the native
** (embedded) time grid of a quantised time value, or by falling back to a standard
** nudging grid, defined in the session context (TODO as of 6/2011). //////////////////////TICKET #810
**
** After (maybe) imposing a change to the target, the change \em notification value
** After (maybe) imposing a change to the target, the _change notification_ value
** needs to be built. This is the time value entity to be forwarded to registered
** listeners. This notification value has to be given as the type \c TI, in accordance
** to the \c time::Control<TI> frontend definition used in the concrete usage situation.
** As this type \c TI might be different to the actual target type, and again different
** listeners. This notification value has to be given as the type `TI`, in accordance
** to the `time::Control<TI>` frontend definition used in the concrete usage situation.
** As this type `TI` might be different to the actual target type, and again different
** to the type of the change handed in, in some cases this involves a second conversion
** step, to represent the current state of the target \c TAR in terms of the interface
** type \c TI.
** step, to represent the current state of the target `TAR` in terms of the interface
** type `TI`.
**
** \par changing quantised (grid aligned) time entities
** ## changing quantised (grid aligned) time entities
**
** The time::Control element includes the capability to handle grid aligned time values,
** both as target and as change/notification value. This ability is compiled in conditionally,
@ -101,11 +101,11 @@
#ifndef LIB_TIME_CONTROL_POLICY_H
#define LIB_TIME_CONTROL_POLICY_H
#include "lib/meta/util.hpp"
#include "lib/time/mutation.hpp"
#include "lib/time/timevalue.hpp"
#include <boost/utility/enable_if.hpp>
#include <type_traits>
#include <functional>
@ -115,7 +115,8 @@ namespace time {
namespace mutation {
using boost::disable_if;
using lib::meta::is_sameType;
using std::__or_;
using std::is_same;
using std::placeholders::_1;
using std::function;
using std::bind;
@ -129,14 +130,14 @@ namespace mutation {
inline bool
isDuration()
{
return is_sameType<T,Duration>::value;
return is_same<T, Duration>::value;
}
template<class T>
inline bool
isTimeSpan()
{
return is_sameType<T,TimeSpan>::value;
return is_same<T, TimeSpan>::value;
}
template<class T>
@ -306,18 +307,18 @@ namespace mutation {
namespace {
template<class T>
struct canMutateDuration
{
static const bool value = is_sameType<T,Duration>::value
|| is_sameType<T,Offset>::value
|| is_sameType<T,int>::value;
};
: __or_< is_same<T,Duration>
, is_same<T,Offset>
, is_same<T,int>
>
{ };
template<class T>
struct canReceiveDuration
{
static const bool value = is_sameType<T,Duration>::value
|| is_sameType<T,TimeSpan>::value;
};
: __or_< is_same<T,Duration>
, is_same<T,TimeSpan>
>
{ };
}

View file

@ -92,7 +92,16 @@ namespace proc {
* A good deal of the active engine code is outside the scope of the
* Proc-Layer, e.g. code located in backend services and plugins.
*/
namespace engine { }
namespace engine {
/**
* Policies, definitions and tweaks to control the actual setup
* and behaviour of the render engine, and the way, render nodes
* are wired and instantiated
*/
namespace config { }
}

View file

@ -53,6 +53,7 @@
#include "lib/meta/configflags.hpp"
#include "lib/meta/util.hpp"
#include "lib/util.hpp"
#include <functional>
@ -184,5 +185,50 @@ namespace config {
using lib::meta::Yes_t;
using lib::meta::No_t;
/**
* Helper template for semi-automatic detection if instantiation is possible.
* Requires help by the template to be tested, which needs to define a type member
* `is_defined`. The embedded metafunction Test can be used as a predicate for
* filtering types which may yield a valid instantiation of the candidate template
* in question.
* @todo 1/2016 is there no better way to achieve this, based on new language features /////////////TICKET #986
* Basically we want a SFINAE helper not only to check if a specific instantiation
* can be formed (which would be trivial), but rather, if a specific instantiation
* has _already been defined_. An automated solution for this problem seems questionable
* by theoretic reasons; such would endanger the "One Definition Rule", since the state
* of definedness of any type may change during the course of a translation unit from
* "unknown" to "declared", "partially defined" to "fully defined". To hinge the existence
* of another type on this transitory state would introduce a dangerous statefulness into
* the meta-language, which is assumed to be stateless.
* @todo what _could_ be done though is to detect if a given template can be _default constructed_,
* which, by logical weakening, implies it has be defined at all. Would that satisfy our
* purpose here?
* @todo 1/2016 also I'm not happy with the name "Instantiation". It should be something like `is_XYZ`
*/
template<template<class> class _CandidateTemplate_>
struct Instantiation
{
template<class X>
class Test
{
typedef _CandidateTemplate_<X> Instance;
template<class U>
static Yes_t check(typename U::is_defined *);
template<class U>
static No_t check(...);
public:
static const bool value = (sizeof(Yes_t)==sizeof(check<Instance>(0)));
};
};
}}} // namespace proc::engine::config
#endif

View file

@ -37,7 +37,6 @@ namespace engine {
using lib::meta::Flags;
using lib::meta::CombineFlags;
using lib::meta::DefineConfigByFlags;
using lib::meta::Instantiation;
using lib::meta::Apply;
using lib::meta::Filter;

View file

@ -30,7 +30,6 @@
#include "lib/meta/generator-combinations.hpp"
#include "proc/asset/meta/time-grid.hpp"
#include "lib/scoped-holder.hpp"
#include "lib/meta/util.hpp"
#include "lib/util.hpp"
#include <boost/lexical_cast.hpp>
@ -195,20 +194,19 @@ namespace test{
namespace { // Implementation: Matrix of individual test combinations
using lib::meta::is_sameType;
template<class T>
inline bool
isDuration()
{
return is_sameType<T,Duration>::value;
return std::is_same<T,Duration>::value;
}
template<class T>
inline bool
isQuTime()
{
return is_sameType<T,QuTime>::value;
return std::is_same<T,QuTime>::value;
}
template<class T>

View file

@ -38,7 +38,6 @@
#include "lib/test/run.hpp"
#include "lib/meta/util.hpp"
#include "lib/format-string.hpp"
#include "lib/meta/generator.hpp"
#include "lib/meta/typelist-manip.hpp"
@ -60,6 +59,7 @@ namespace lib {
namespace meta {
namespace test {
using proc::engine::config::Instantiation;
namespace { // internal definitions

View file

@ -43,9 +43,11 @@
#include "lib/meta/typelist-manip.hpp"
#include "meta/typelist-diagnostics.hpp"
#include <type_traits>
#include <iostream>
using ::test::Test;
using std::is_same;
using std::cout;
using std::endl;
@ -139,9 +141,9 @@ namespace test {
CHECK (6 == e1);
CHECK (7 == e2);
CHECK ((is_sameType<NullType, E3> ::value));
CHECK ((is_sameType<NullType, Nil> ::value));
CHECK ((is_sameType<NullType, Irrelevant>::value));
CHECK ((is_same<NullType, E3> ::value));
CHECK ((is_same<NullType, Nil> ::value));
CHECK ((is_same<NullType, Irrelevant>::value));
}