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:
commit
d9141931a9
4 changed files with 210 additions and 0 deletions
|
|
@ -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'])
|
||||
]
|
||||
|
||||
#
|
||||
|
|
|
|||
28
research/clang-static-init-1.cpp
Normal file
28
research/clang-static-init-1.cpp
Normal 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;
|
||||
}
|
||||
40
research/clang-static-init-2.cpp
Normal file
40
research/clang-static-init-2.cpp
Normal 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
|
||||
140
research/clang-static-init.hpp
Normal file
140
research/clang-static-init.hpp
Normal 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
|
||||
Loading…
Reference in a new issue