//////////////////////////////////////////////// // dependent_static.h #ifndef DEPENDENT_STATIC__H #define DEPENDENT_STATIC__H #include <assert.h> #include <vector> #include <algorithm> #include <stdexcept> namespace Private { class no_type {}; struct no_type_as_param { no_type_as_param( no_type &) {} }; template< class type> struct ref_wrapper { ref_wrapper( type & val) : m_ref( val) {} type & m_ref; }; // transform no_type into no_type_as_param // the rest is transformed into ref_wrapper template< class type> struct type_as_param_impl { typedef ref_wrapper< type> result; }; template<> struct type_as_param_impl< no_type> { typedef no_type_as_param result; }; // transforms no_type into no_type_as_param; // anything else (T) is transformed into ref_wrapper< T> template< class type> inline typename type_as_param_impl< type>::result type_as_param( type & val) { return val; } // 2 Params template< class type, class type01, class type02 > inline void call_initializer_impl( type * & p, ref_wrapper< type01> val01, ref_wrapper< type02> val02 ) { p = new type( val01.m_ref, val02.m_ref ); } // 1 Param template< class type, class type01 > inline void call_initializer_impl( type * & p, ref_wrapper< type01> val01, no_type_as_param ) { p = new type( val01.m_ref ); } // 0 Params template< class type> inline void call_initializer_impl( type * & p, no_type_as_param, no_type_as_param ) { p = new type(); } // delegate to call_initializer_impl template< class type, class type01 , class type02> inline void call_initializer( type * & p, type01 & val01 , type02 & val02) { call_initializer_impl( p, type_as_param( val01), type_as_param( val02) ); } } // namespace Private template< class type> struct collect_parameters_base { //initializes this pointer virtual void initialize(type * & p) = 0; }; template< class type, class type01 = Private::no_type, class type02 = Private::no_type> struct collect_parameters : public collect_parameters_base< type> { collect_parameters( // we pass params by value - this way, // we can even pass functions as arguments! type01 val01 = type01(), type02 val02 = type02() ) : m_val01( val01), m_val02( val02) {} void initialize(type * & p) { // we're initializing p now!!! assert( p == 0); Private::call_initializer( p, m_val01, m_val02); } private: type01 m_val01; type02 m_val02; }; // function new_collect_parameters: // returns a new collect_parameters object, // based on its arguments template< class type, class type01 , class type02 > inline collect_parameters_base< type> * new_collect_parameters( type01 val01 , type02 val02) { return new collect_parameters<type, type01, type02>( val01, val02); } namespace Private { // forward declaration struct dependent_static_base; } class all_dependent_statics { // don't allow creation except for our instance() all_dependent_statics() {} public: void add_dependent_static( Private::dependent_static_base * p) { m_aStatics.push_back( p); } inline static void initialize_statics(); inline static all_dependent_statics & instance() { static all_dependent_statics inst; return inst; } private: std::vector< Private::dependent_static_base*> m_aStatics; }; namespace Private { struct dependent_static_base { dependent_static_base() { ::all_dependent_statics::instance().add_dependent_static( this); } virtual void initialize_static() = 0; }; // helper inline void do_initialize_static( dependent_static_base *p) { p->initialize_static(); } }; // initialize our statics inline void all_dependent_statics::initialize_statics() { all_dependent_statics & inst = all_dependent_statics::instance(); std::for_each( inst.m_aStatics.begin(), inst.m_aStatics.end(), Private::do_initialize_static); } /* postpones initialization of static variable (it's initialized when you call initialize_static) */ struct dependent_static : // so that we can register this object, to be initialized later private Private::dependent_static_base { // non-copyiable typedef dependent_static< type> this_class; dependent_static( const this_class &); this_class operator=( const this_class &); public: // 2 Params template< class type01, class type02 > dependent_static( type01 val01, type02 val02) : m_pVal( 0), m_pInitializer( new_collect_parameters< type>( val01, val02)) {} // 1 Param template< class type01 > dependent_static( type01 val01) : m_pVal( 0), m_pInitializer( new_collect_parameters< type>( val01, Private::no_type() )) {} // 0 Params dependent_static() : m_pVal( 0), m_pInitializer( new_collect_parameters< type>( Private::no_type(), Private::no_type() )) {} ~dependent_static() { delete m_pInitializer; } /* virtual */ void initialize_static() { if ( m_pVal == 0) m_pInitializer->initialize( m_pVal); else // already initialized!!! assert( false); } operator type &() { check_val(); return *m_pVal; } operator const type&() const { check_val(); return *m_pVal; } private: void check_val() const { if ( m_pVal == 0) throw std::runtime_error( "dependent_static used too early!" " (before calling 'all_dependent_statics::initialize_statics()' )"); } private: collect_parameters_base< type> *m_pInitializer; type * m_pVal; }; // dependent_static #endif // DEPENDENT_STATIC__H |