diff --git a/research/SConscript b/research/SConscript index cde733bf9..11f58d5c9 100644 --- a/research/SConscript +++ b/research/SConscript @@ -9,10 +9,12 @@ Import('env core support_lib') envR = env.Clone() +envR.Append(CPPPATH='research') # envR.Append(CCFLAGS=' -O3 ') # build additional test and administrative tools.... experiments = [ envR.Program('try', ['try.cpp'] + support_lib) #### to try out some feature... + , envR.Program('clang-static-init', ['clang-static-init-1.cpp', 'clang-static-init-2.cpp']) ] # diff --git a/research/clang-static-init-1.cpp b/research/clang-static-init-1.cpp new file mode 100644 index 000000000..6c473de41 --- /dev/null +++ b/research/clang-static-init-1.cpp @@ -0,0 +1,28 @@ + +#include "clang-static-init.hpp" + + +test::Subject& +localFunction() +{ + return test::fab.get(); +} + + +int +main (int, char**) + { + cout << "\nStart Testcase: invoking two instances of the configurable singleton factory...\n\n"; + + test::Subject& ref1 = test::fab.get(); + test::Subject& sub2 = test::fabricate(); ///NOTE: invoking get() from within another compilation unit reveales the problem + test::Subject& sub3 = localFunction(); + + cout << "sub1=" << &ref1 + << "\nsub2="<< &sub2 + << "\nsub3="<< &sub3 + << "\n"; + + + return 0; + } diff --git a/research/clang-static-init-2.cpp b/research/clang-static-init-2.cpp new file mode 100644 index 000000000..c23468837 --- /dev/null +++ b/research/clang-static-init-2.cpp @@ -0,0 +1,40 @@ + +#include "clang-static-init.hpp" + + + +namespace test { + + + int Subject::creationCount = 0; + + Subject::Subject() + { + ++creationCount; + std::cout << "Subject("< shall_build_a_Subject_instance; + } + + /** + * instance of the singleton factory + * @note especially for this example we're using just \em one + * shared instance of the factory. + * Yet still, the two (inlined) calls to the get() function + * access different addresses for the embedded singleton instance + */ + AccessPoint fab(shall_build_a_Subject_instance); + + + Subject& + fabricate() + { + return fab.get(); + } + + +} // namespace test diff --git a/research/clang-static-init.hpp b/research/clang-static-init.hpp new file mode 100644 index 000000000..272e76d08 --- /dev/null +++ b/research/clang-static-init.hpp @@ -0,0 +1,140 @@ + +#include + +using std::cout; + + +namespace test { + + + + /* === Layer-1: a singleton factory based on a templated static variable === */ + + template class Fac ///< Policy: actual factory to create the instance + > + struct Holder + { + static I* instance; + + I& + get() + { + if (!instance) + { + cout << "Singleton Factory: invoke Fabrication ---> address of static instance variable: "<<&instance<<"...\n"; + + instance = Fac::create(); + } + return *instance; + } + }; + + /** + * allocate storage for the per-type shared + * (static) variable to hold the singleton instance + */ + template class F + > + I* Holder::instance; + + + + + template + struct Factory + { + static C* + create() + { + return new C(); + } + }; + + + + + + /* === Layer-2: configurable product type === */ + + template + struct Adapter + { + typedef I* FactoryFunction (void); + + static FactoryFunction* factoryFunction; + + + template + static I* + concreteFactoryFunction() + { + return static_cast (Factory::create()); + } + + + template + struct AdaptedConfigurableFactory + { + static X* + create() + { + return (*factoryFunction)(); + } + }; + }; + + /** storage for the per-type shared function pointer to the concrete factory */ + template + typename Adapter::FactoryFunction* Adapter::factoryFunction; + + + + template + struct TypeInfo { }; + + + + /** + * Singleton factory with the ability to configure the actual product type C + * only at the \em definition site. Users get to see only the interface type T + */ + template + struct ConfigurableHolder + : Holder::template AdaptedConfigurableFactory> + { + /** define the actual product type */ + template + ConfigurableHolder (TypeInfo) + { + Adapter::factoryFunction = &Adapter::template concreteFactoryFunction; + } + }; + + + + + + /* === Actual usage: Test case fabricating Subject instances === */ + + struct Subject + { + static int creationCount; + + Subject(); + + }; + + typedef ConfigurableHolder AccessPoint; + + extern AccessPoint fab; + + + + Subject& fabricate(); + + + + +} // namespace test