investigation of a problem with Clang

posted also to Stackoverflow. http://stackoverflow.com/questions/19212474/clang-links-to-different-locations-when-referring-a-templated-static-variable-fr
This commit is contained in:
Fischlurch 2013-10-07 02:03:14 +02:00
commit d9141931a9
4 changed files with 210 additions and 0 deletions

View file

@ -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'])
]
#

View file

@ -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;
}

View file

@ -0,0 +1,40 @@
#include "clang-static-init.hpp"
namespace test {
int Subject::creationCount = 0;
Subject::Subject()
{
++creationCount;
std::cout << "Subject("<<creationCount<<")\n";
}
namespace {
TypeInfo<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

View file

@ -0,0 +1,140 @@
#include <iostream>
using std::cout;
namespace test {
/* === Layer-1: a singleton factory based on a templated static variable === */
template<typename I ///< Interface of the product type
,template <class> 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<I>::create();
}
return *instance;
}
};
/**
* allocate storage for the per-type shared
* (static) variable to hold the singleton instance
*/
template<typename I
,template <class> class F
>
I* Holder<I,F>::instance;
template<typename C>
struct Factory
{
static C*
create()
{
return new C();
}
};
/* === Layer-2: configurable product type === */
template<typename I>
struct Adapter
{
typedef I* FactoryFunction (void);
static FactoryFunction* factoryFunction;
template<typename C>
static I*
concreteFactoryFunction()
{
return static_cast<I*> (Factory<C>::create());
}
template<typename X>
struct AdaptedConfigurableFactory
{
static X*
create()
{
return (*factoryFunction)();
}
};
};
/** storage for the per-type shared function pointer to the concrete factory */
template<typename I>
typename Adapter<I>::FactoryFunction* Adapter<I>::factoryFunction;
template<typename C>
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<typename T>
struct ConfigurableHolder
: Holder<T, Adapter<T>::template AdaptedConfigurableFactory>
{
/** define the actual product type */
template<typename C>
ConfigurableHolder (TypeInfo<C>)
{
Adapter<T>::factoryFunction = &Adapter<T>::template concreteFactoryFunction<C>;
}
};
/* === Actual usage: Test case fabricating Subject instances === */
struct Subject
{
static int creationCount;
Subject();
};
typedef ConfigurableHolder<Subject> AccessPoint;
extern AccessPoint fab;
Subject& fabricate();
} // namespace test