Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
kwargs/include/kwargs.h
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
178 lines (146 sloc)
5.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file kwargs.h | |
* @author Josh Bialkowski <josh.bialkowski@gmail.com> | |
* @brief tooling for python-like kwargs in c++ | |
*/ | |
/// classes and templates used by kwargs library | |
namespace kw { | |
/// parameter storage for type T within a parameter pack | |
template <int tag, typename T> | |
struct Arg { | |
T v; | |
Arg(T v) : v(v) {} | |
}; | |
/// signifies that the parameter should be passed by reference | |
template <typename T> | |
struct RefWrap { | |
T& v; | |
RefWrap(T& v) : v(v) {} | |
}; | |
/// signifies the parameter should be passed by const reference | |
template <typename T> | |
struct ConstRefWrap { | |
const T& v; | |
ConstRefWrap(const T& v) : v(v) {} | |
}; | |
/// forces an argument to be passed by reference | |
template <typename T> | |
RefWrap<T> Ref(T& v){ return RefWrap<T>(v); } | |
/// forces an argument to be passed by const reference | |
template <typename T> | |
const ConstRefWrap<T> ConstRef(const T& v) { return ConstRefWrap<T>(v); } | |
/// the type of a global symbol used as a key for key-values pairs in the | |
/// kwargs parameter pack | |
template <int tag> | |
struct Key { | |
template <typename T> | |
Arg<tag,T> operator=(T v) { return v; } | |
template <typename T> | |
Arg<tag,T&> operator=(RefWrap<T> vw) { return vw.v; } | |
template <typename T> | |
Arg<tag,const T&> operator=(ConstRefWrap<T> vw) { return vw.v; } | |
}; | |
/// storage for kwargs parameter pack | |
template <typename... Args> | |
struct ParamPack{}; | |
/// template meta-function contains a static boolean variable 'result' which | |
/// is true if tag is in the list of kwargs and false if not | |
template <int tag, typename... Args> | |
struct ContainsTag {}; | |
/// template meta function provides a member typedef Result which evaluates | |
/// to T if Arg<tag,T> is in Args... or Default if it is not | |
template <int tag, typename Default, typename... Args> | |
struct TypeOfTagDefault {}; | |
/// provides static member Get() with implementations depending on whether | |
/// or not tag is in Args... | |
template <int tag, bool exists, typename Default, typename... Args> | |
struct GetImpl{}; | |
/// given a parameter pack, retrieves and return sthe parameter tagged with tag, | |
/// or else returns a default value if tag is not in Args... | |
template <int tag, typename Default, typename... Args> | |
typename TypeOfTagDefault<tag,Default,Args...>::Result | |
Get(ParamPack<Args...>& pack, Default d) { | |
return | |
GetImpl<tag,ContainsTag<tag,Args...>::result,Default,Args...>::Get(pack,d); | |
} | |
/// given a parameter pack, retrieves and return sthe parameter tagged with tag, | |
/// or else returns a default value if tag is not in Args... | |
template <int tag, typename Default, typename... Args> | |
typename TypeOfTagDefault<tag,Default,Args...>::Result | |
Get(ParamPack<Args...>& pack, Key<tag> key, Default d) { | |
return | |
GetImpl<tag,ContainsTag<tag,Args...>::result,Default,Args...>::Get(pack,d); | |
} | |
} //< namespace kw | |
// ---------------------------------------------------------------------------- | |
// Danger!!! Horrible implementation details below!!! | |
// Continue at your own risk! | |
// ---------------------------------------------------------------------------- | |
#ifndef DOXYGEN_IGNORE | |
namespace kw { | |
/// specialization for recursion, provides storage for the current type in the | |
/// type list, then recursively derives from the remaining types in the type | |
/// list | |
template <typename Head, typename... Tail> | |
struct ParamPack<Head,Tail...> | |
: Head, | |
ParamPack<Tail...> { | |
ParamPack( Head head, Tail... tail ) | |
: Head(head), | |
ParamPack<Tail...>(tail...) {} | |
}; | |
/// specialization for base case, provides storage for the last type in the | |
/// type list | |
template <typename Tail> | |
struct ParamPack<Tail> : Tail { | |
ParamPack( Tail tail ) : Tail(tail) {} | |
}; | |
/// specialization for recursion | |
template <int tag, typename First, typename... Rest> | |
struct ContainsTag<tag,First,Rest...> { | |
static const bool result = ContainsTag<tag, Rest...>::result; | |
}; | |
/// specialization for when the Arg<tag,T> type is found | |
template <int tag, typename T, typename... Rest> | |
struct ContainsTag<tag, Arg<tag,T>, Rest...> { | |
static const bool result = true; | |
}; | |
/// specialization for when tag is not in the type list | |
template <int tag> | |
struct ContainsTag<tag> { | |
static const bool result = false; | |
}; | |
/// specialization for recursion | |
template <int tag, typename Default, typename Head, typename... Tail> | |
struct TypeOfTagDefault<tag, Default, Head, Tail...> { | |
typedef typename TypeOfTagDefault<tag, Default, Tail...>::Result Result; | |
}; | |
/// specialization for when Arg<tag,T> is found | |
template <int tag, typename Default, typename T, typename... Tail> | |
struct TypeOfTagDefault<tag, Default, Arg<tag, T>, Tail...> { | |
typedef T Result; | |
}; | |
/// specialization for when Arg<tag,T> is not in the type list | |
template <int tag, typename Default> | |
struct TypeOfTagDefault<tag,Default> { | |
typedef Default Result; | |
}; | |
/// specialization for when tag is not in Args..., returns the default value | |
template <int tag, typename Default, typename... Args> | |
struct GetImpl<tag,false,Default,Args...>{ | |
static Default Get(ParamPack<Args...>& pack, Default d) { | |
return d; | |
} | |
}; | |
/// specialization for when tag is in Args... returns the value corresponding | |
/// to tag | |
template <int tag, typename Default, typename... Args> | |
struct GetImpl<tag,true,Default,Args...>{ | |
static typename TypeOfTagDefault<tag,Default,Args...>::Result Get( | |
ParamPack<Args...>& pack, Default d) { | |
typedef typename TypeOfTagDefault<tag,Default,Args...>::Result StorageType; | |
return static_cast<Arg<tag,StorageType>&>(pack).v; | |
} | |
}; | |
} //< namespace kw | |
#endif // DOXYGEN_IGNORE |