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:
parent
fec0a88753
commit
ff7ac5523f
8 changed files with 109 additions and 87 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
>
|
||||
{ };
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue