Created
September 4, 2013 08:21
-
-
Save kris-jusiak/6434203 to your computer and use it in GitHub Desktop.
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
#ifndef DI_HPP | |
#define DI_HPP | |
#include <type_traits> | |
#include <utility> | |
#include <boost/mpl/has_xxx.hpp> | |
#include <boost/mpl/aux_/yes_no.hpp> | |
#define CTOR(T, ...) \ | |
static void ctor(__VA_ARGS__); \ | |
T(__VA_ARGS__) | |
namespace { | |
template<typename TArg> | |
class make_plain | |
{ | |
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) | |
template<typename T> | |
struct remove_accessors | |
: std::remove_cv< | |
typename std::remove_pointer< | |
typename std::remove_reference<T>::type | |
>::type | |
> | |
{ }; | |
template<typename T, typename = void> | |
struct deref_element_type | |
{ | |
typedef T type; | |
}; | |
template<typename T> | |
struct deref_element_type< | |
T | |
, typename std::enable_if< | |
has_element_type<T>::value | |
>::type | |
> | |
{ | |
typedef typename T::element_type type; | |
}; | |
public: | |
typedef typename deref_element_type< | |
typename remove_accessors< | |
typename deref_element_type< | |
typename remove_accessors<TArg>::type | |
>::type | |
>::type | |
>::type type; | |
}; | |
template<typename T> | |
class scope | |
{ | |
public: | |
template<typename... Args> | |
scope(Args&&... args) { | |
ptr_ = new T(std::forward<Args>(args)...); | |
} | |
~scope() { | |
} | |
operator T() const { | |
return *ptr_; | |
} | |
template<typename I> | |
operator std::shared_ptr<I>() const { | |
return std::shared_ptr<I>(ptr_); | |
} | |
template<typename I> | |
operator std::unique_ptr<I>() const { | |
return std::unique_ptr<I>(ptr_); | |
} | |
private: | |
T* ptr_; | |
}; | |
template<typename... TDeps> | |
class di | |
{ | |
template<typename T> | |
class has_ctor | |
{ | |
template<typename C> static boost::mpl::aux::yes_tag test(decltype(&C::ctor)); | |
template<typename> static boost::mpl::aux::no_tag test(...); | |
public: | |
static const bool value = sizeof(test<T>(0)) == sizeof(boost::mpl::aux::yes_tag); | |
}; | |
template<typename T> | |
using plain = typename make_plain<T>::type; | |
template< | |
typename T | |
, typename Ctor = plain<T> | |
> | |
using ctor = decltype(Ctor::ctor); | |
template<typename T> | |
class create_impl { }; | |
template<typename... TArgs> | |
class create_impl<void(TArgs...)> | |
{ | |
template<typename T, bool V = true> | |
using enable_if_ctor = | |
typename std::enable_if< | |
has_ctor<plain<T>>::value == V | |
, scope<T> | |
>::type; | |
template<typename T> | |
using disable_if_ctor = enable_if_ctor<T, false>; | |
public: | |
template<typename T> | |
static scope<plain<T>> execute() { | |
return scope<plain<T>>(execute_impl<TArgs>()...); | |
} | |
private: | |
template<typename T> | |
static enable_if_ctor<T> execute_impl() { | |
return create_impl<ctor<T>>::template execute<T>(); | |
} | |
template<typename T> | |
static disable_if_ctor<T> execute_impl() { | |
return scope<T>(); | |
} | |
}; | |
public: | |
template<typename T> | |
scope<T> create() const { | |
return create_impl<ctor<T>>::template execute<T>(); | |
} | |
}; | |
} // namespace | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment