I have an issue when trying to initialize static members of a static class template.
Basically, what I thought this approach would be useful for:
I have a lot of objects, which are of course all of the same Base type but they have differing object types. I just want to manipulate these objects, that's why I decided to use a static template as there are quite a number of different types these object can consist of.
However, for logging and options passing I wanted to add the corresponding members to the template whithout having to write initializers for every derived static class.
Please note that the following code is not actually working, because there is some SDK involved.
I'm just aksing for the right approach, not right code.
Thanks in advance. :)
template.h:
#ifndef _TEMPLATE_H
#define _TEMPLATE_H
#include "stats.h"
template<class T>
class TemplateObj
{
public:
static void SetParameters(const Options& options)
{
T::_options = options; // Is this even possible?
T::Init();
T::DoStuff(_options);
}
protected:
static void Message() { stats.Print("Message from Template static method"); }
static Stats& TemplateObj<T>::stats = Stats::GetInstance(); // This will not work as this is a non-trivial initializer, how to do it correctly? Stats::GetInstance() retrieves a singleton instance
static Options& TemplateObj<T>::_options; // Possible?
};
#endif
derived.h:
#ifndef _DERIVED_H
#define _DERIVED_H
#include "template.h"
class Derived :TemplateObj < Derived >
{
public:
static void Init();
static void DoStuff(Options& options)
};
#endif
derived.cpp:
#include "derived.h"
void Derived::Init()
{
// Init stuff here
TemplateObj::Message(); // Call static method from template directly
}
void Derived::DoStuff(Options& options)
{
// Do something with options
stats.Print("Message from derived static method."); // Access to "stats" here. "stats" should be declared and initialized inside the template.
options.Load(); // Example
}
main.h
#include "derived.h"
main()
{
TemplateObj<Derived>::SetParameters(new Options);
}
Basically, you don't need to put TemplateObj<T>:: before the function definition if it is inside the class definition. The following two are both valid:
template<class T>
class A{
void func( void );
};
template<class T>
void A<T>::func() { /* Okay */ }
template<class T>
class B {
void func( void ){ /* Okay */ }
};
In your case, replace the following static Stats& TemplateObj<T>::stats = Stats::GetInstance(); with static Stats& stat() { return Stats::GetInstance(); }
And the following static Options& TemplateObj<T>::_options; with this static Options& _options;.
On the other hand, replace this T::_options = options; with TemplateObj<T>::_options = options;.
Related
This is about the following setup of an application that uses (abstract) functionality from a *.dll and a static library and which causes read access violation at last (further details are provided below the code):
... static library ...
// InterfaceWrap.h
//-----------
// dummy include
#include <SomeTClass.h>
template<typename T>
class InterfaceWrap
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
~InterfaceWrap();
void AnyAction();
};
template<typename T>
InterfaceWrap<T>::InterfaceWrap() {
m_somePtr = std::make_shared<SomeTClass<T>>();
}
template<typename T>
void InterfaceWrap<T>::AnyAction() {
m_somePtr->SomeAction();
}
... *.dll ...
// Proc.h
//-----------
// correct forward declaration?
class ThisInterface;
#include <InterfaceWrap.h>
class DLL Proc
{
std::shared_ptr<InterfaceWrap <ThisInterface>> m_interfaceWrapPtr;
public:
Proc();
~Proc();
InterfaceWrap<ThisInterface>* GetPtr();
};
// Proc.cpp
//-----------
// what about forward declaration here?
Proc::Proc() {
m_interfaceWrapPtr = std::make_shared<InterfaceWrap<ThisInterface>>();
}
InterfaceWrap<ThisInterface>* Proc::GetPtr() {
return m_interfaceWrapPtr.get();
}
... the application ...
// main.cpp
//-----------
#include <Proc.h>
// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>
class ThisInterfaceA {
public:
using Type1 = ThisType01;
using Type2 = ThisType02;
};
class ThisInterfaceB { // not needed here but perhaps illustrative
public:
using Type1 = ThisType11;
using Type2 = ThisType12;
};
using ThisInterface = ThisInterfaceA;
int main(int argc, char * argv[])
{
Proc proc;
proc.GetPtr()->AnyAction();
return 0;
}
The crucial intention behind this construction is to keep the Proc and InterfaceWrap classes as abstract as possible, i.e., having them not depending directly on a chosen "interface" like ThisInterfaceA. Moreover I would like to keep the feature, that Proc is not a template class.
Obviously there are problems, of which I'm not sure how to resolve them nicely:
The line using ThisInterface = ThisInterfaceA does not work as it leads to compilation errors for the dll source codes, basically saying that ThisInterface is not known. If however, instead of this line, e.g., ThisInterfaceA is replaced by ThisInterface directly, everything compiles and links fine, at least.
Even if everything compiles and links (compare 1.), there would ultimately occur a read access violation, which concerns m_interfaceWrapPtr or m_somePtr.
What I wonder in particular is, whether properly applied forward declaration is capable of resolving the above issues and allowing to keep the feature that Proc is that abstract (or even more?) and not a template class?
Why not use real interface and DIP:
struct IAnyAction
{
virtual ~IAnyAction() = default;
virtual void AnyAction() = 0;
};
class Proc
{
std::shared_ptr<IAnyAction> m_interface;
public:
Proc(std::shared_ptr<IAnyAction> anyAction) : m_interface(anyAction) {}
IAnyAction* GetPtr() { return m_interface.get(); }
};
template<typename T>
class InterfaceWrap : public IAnyAction
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
void AnyAction() override { m_somePtr->SomeAction(); }
};
and
using ThisInterface = ThisInterfaceA; // For easy/quick way to change concrete type for interface
int main()
{
Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());
proc.GetPtr()->AnyAction();
}
In case anyone is interested, in what follows I provide the edited example code (from the beginning) as it finally works for me.
The solution is basically the answer of Jarod42 (Perhaps this overall approach may not be the most elegant one, as pointed out in the other comments. However, I guess some purposes may justify it).
However, there is one little thing added: casted void pointer arguments. To me this turns out useful when extending the original problem towards, e.g., the member AnyAction having an argument of yet unspecified but "known" type.
... static library ...
// InterfaceWrap.h
//-----------
// dummy include
#include <SomeTClass.h>
struct IAnyAction
{
virtual ~IAnyAction() = default;
virtual void AnyAction(void* arg) = 0;
};
template<typename T>
class InterfaceWrap : public IAnyAction
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
void AnyAction(void* arg);
};
template<typename T>
InterfaceWrap<T>::InterfaceWrap(){
m_somePtr = std::make_shared<SomeTClass<T>>();
}
template<typename T>
void InterfaceWrap<T>::AnyAction(void* arg) override {
auto thisArg = static_cast<T::Type1*>(arg);
m_somePtr->SomeAction(*thisArg);
}
... *.dll ...
// Proc.h
//-----------
#include <InterfaceWrap.h>
class DLL Proc
{
std::shared_ptr<IAnyAction> m_interfaceWrapPtr;
public:
Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr);
~Proc();
IAnyAction* GetPtr();
};
// Proc.cpp
//-----------
Proc::Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr) : m_interfaceWrapPtr(interfaceWrapPtr) {
}
IAnyAction* Proc::GetPtr() {
return m_interfaceWrapPtr.get();
}
... the application ...
// main.cpp
//-----------
#include <Proc.h>
// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>
class ThisInterfaceA {
public:
using Type1 = ThisType01;
using Type2 = ThisType02;
};
class ThisInterfaceB { // not needed here but perhaps illustrative
public:
using Type1 = ThisType11;
using Type2 = ThisType12;
};
using ThisInterface = ThisInterfaceA;
int main(int argc, char * argv[])
{
Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());
auto type1 = std::make_shared<ThisInterface::Type1*>();
proc.GetPtr()->AnyAction(type1.get());
return 0;
}
So, i've been working in a project of a System API, and i'm trying to figure out how to avoid circular dependency in the definition of a static template method. The thing is, template methods cannot be defined in a separeted cpp, and i cannot define it in the header file either because that would cause circular dependency:
flow.h:
#include "system.h"
#include "flowImpl.h" //circular dependency
#include <vector>
#ifndef TRAB_INDIVIDUAL_FLOW_H
#define TRAB_INDIVIDUAL_FLOW_H
typedef std::vector<System*>::iterator SystemIterator;
class Flow {
public:
//-----------------------------------
//What's giving me problems
template <typename T_FLOW_IMPL>
static Flow* createFlow() {
return FlowImpl::createFlow<T_FLOW_IMPL>();
}
template <typename T_FLOW_IMPL>
static Flow* createFlow(System* s1,System* s2,std::string str) {
return FlowImpl::createFlow<T_FLOW_IMPL>(s1,s2,str);
}
//-----------------------------------
virtual double executeFunction()=0;
virtual System* getTargetSys()=0;
virtual System* getSourceSys()=0;
virtual std::string getName()=0;
virtual void changeTargetSys(SystemIterator)=0;
virtual void changeSourceSys(SystemIterator)=0;
virtual void changeTargetSys(System*)=0;
virtual void changeSourceSys(System*)=0;
};
#endif
flowImpl.h
#include "flow.h"
#ifndef TRAB_INDIVIDUAL_FLOWIMPL_H
#define TRAB_INDIVIDUAL_FLOWIMPL_H
class ModelImpl;
class FlowImpl : public Flow {
friend ModelImpl;
friend Flow;
private:
FlowImpl();
FlowImpl(System*,System*,std::string);
FlowImpl(Flow*,std::string);
std::string name;
System* source_sys;
System* target_sys;
template <typename T_FLOW_IMPL>
static Flow* createFlow() {
Flow* f = new T_FLOW_IMPL();
return f;
}
template <typename T_FLOW_IMPL>
static Flow* createFlow(System*,System*,std::string) {
Flow* f = new T_FLOW_IMPL(s1,s2,str);
return f;
}
protected:
double getSourceQ();
double getTargetQ();
public:
virtual ~FlowImpl();
bool operator==(FlowImpl&);
FlowImpl& operator=(const FlowImpl&);
virtual double executeFunction()=0;
System* getTargetSys() override;
System* getSourceSys() override;
std::string getName() override;
void changeTargetSys(SystemIterator) override;
void changeSourceSys(SystemIterator) override;
void changeTargetSys(System*) override;
void changeSourceSys(System*) override;
};
#endif
I tried using forward declaration, but with no success, because i cannot forward declare a method of another class (being FlowImpl::createFlow()), only the entire class.
My objective in those static methods are to make a Method Factory with static members using interfaces, and since i cannot use "virtual" for static template methods, my only option was to implement it on the interface, and inside the implementation call the same static method but for the subclass, which have the atributes for allocation. As I said, I cannot do that either because template methods can't be implemented in a different file, and if I define it inside the header it will cause circular dependency with "flowImpl.h".
Thanks for reading! Any ambiguities or lack of information please report so i can clarify it.
Remove the #include of flowImpl.h from flow.h, and forward-declare the template class method:
class Flow {
public:
// ...
template <typename T_FLOW_IMPL>
static Flow* createFlow();
Then finish the job in flowImpl.h, after the implementation class's declaration:
class flowImpl {
// ...
};
template <typename T_FLOW_IMPL>
static Flow* Flow::createFlow() {
return FlowImpl::createFlow<T_FLOW_IMPL>();
}
Do the same for the other template method, as well. Note that whatever needs to call these class methods will have to include the flowImpl.h header file, though.
I´ve created the following Event class:
Event.h
#ifndef EVENT_H
#define EVENT_H
#include<string>
template<typename T>
class Event
{
public:
T fnktptr; //Error: field ‘Event<int()>::fnktptr’ invalidly declared function type
Event();
virtual ~Event();
};
#endif // EVENT_H
Event.cpp
#include "Event.h"
template<typename T>
Event<T>::Event()
{
//ctor
}
template<typename T>
Event<T>::~Event()
{
//dtor
}
// No need to call this TemporaryFunction() function,
// it's just to avoid link error.
void TemporaryFunction ()
{
Event<int> TempObj;
}
Now I tested it with the following code and it works:
Event<int> event;
int t = 5;
event.fnktptr = t;
But finally, I want to use it with a functor like this:
Event<decltype(consumeInt)> event;
event.fnktptr = consumeInt;
But now I get a Error in the Event.h file:
T fnktptr; //Error: field ‘Event<int()>::fnktptr’ invalidly declared function type
Based on your latest comments, I would say a std::function<> is the best way forward. The example code below assumes you just want to call fnktptr and don't care about the result.
#include <functional>
class Event
{
public:
std::function<void ()> fnktptr;
Event();
virtual ~Event();
};
If you need to capture the result, you will not be able to arbitrarily have different returns for each Event object. You either must pick one or use something like boost::variant<>.
template<class T>
class Event
{
public:
std::function<T ()> fnktptr;
Event();
virtual ~Event();
};
This would allow you to create Event<int> objects for instance to use with consumeInt().
Example:
Event<int> event;
event.fnktptr = consumeInt;
I know there is a initailzer trick to forcing a global object to be constructed regardless of where it is used. This is used for std::cout i believe.
#ifndef GUARD_H
#define GUARD_H
class Magical
{
// default constructor and such...
};
class Init
{
public:
Init();
};
extern Magical& magic;
namespace
{
Init __magical_initializer; // works as this object is constructed in every source file it is included in
}
#endif
src:
#include "magical.h"
#include <new>
static int count; // believe there is a spec somewhere which states global integers are initialized with zero
static alignas(Magical) char buffer[sizeof(Magical)];
Magical& magic = *reinterpret_cast<Magical*>(buffer);
Init::Init()
{
if(!count++)
{
new(buffer) Magical;
}
}
I was wondering if there was a template equivalent to this, as such my code would look something like this:
template<typename T>
class Base
{
static Magical<T> __private; // need this constructor to be called.
};
// usage:
class SomeClass : public Base<SomeClass>
{
};
No way to solve this problem as templates can't exist in source files.
Why does following code raise an exception (in createObjects call to map::at)
alternativly the code (and its output) can be viewed here
intererestingly the code works as expected if the commented lines are uncommented with both microsoft and gcc compiler (see here), this even works with initMap as ordinary static variable instead of static getter.
The only reason for this i can think of is that the order of initialization of the static registerHelper_ object (factory_helper_)and the std::map object (initMap) are wrong, however i cant see how that could happen, because the map object is constructed on first usage and thats in factory_helper_ constructor, so everything should be alright shouldnt it ?
I am even more suprised that those doNothing() lines fix the issue, because that call to doNothing() would happen after the critical section (which currently fails) is passed anyway.
EDIT: debugging showed, that without the call to factory_helper_.doNothing(), the constructor of factory_helper_ is never called.
#include <iostream>
#include <string>
#include <map>
#define FACTORY_CLASS(classtype) \
extern const char classtype##_name_[] = #classtype; \
class classtype : FactoryBase<classtype,classtype##_name_>
namespace detail_
{
class registerHelperBase
{
public:
registerHelperBase(){}
protected:
static std::map<std::string, void * (*)(void)>& getInitMap() {
static std::map<std::string, void * (*)(void)>* initMap = 0;
if(!initMap)
initMap= new std::map<std::string, void * (*)(void)>();
return *initMap;
}
};
template<class TParent, const char* ClassName>
class registerHelper_ : registerHelperBase {
static registerHelper_ help_;
public:
//void doNothing(){}
registerHelper_(){
getInitMap()[std::string(ClassName)]=&TParent::factory_init_;
}
};
template<class TParent, const char* ClassName>
registerHelper_<TParent,ClassName> registerHelper_<TParent,ClassName>::help_;
}
class Factory : detail_::registerHelperBase
{
private:
Factory();
public:
static void* createObject(const std::string& objclassname) {
return getInitMap().at(objclassname)();
}
};
template <class TClass, const char* ClassName>
class FactoryBase {
private:
static detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> factory_helper_;
static void* factory_init_(){ return new TClass();}
public:
friend class detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName>;
FactoryBase(){
//factory_helper_.doNothing();
}
virtual ~FactoryBase(){};
};
template <class TClass, const char* ClassName>
detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> FactoryBase<TClass,ClassName>::factory_helper_;
FACTORY_CLASS(Test) {
public:
Test(){}
};
int main(int argc, char** argv) {
try {
Test* test = (Test*) Factory::createObject("Test");
}
catch(const std::exception& ex) {
std::cerr << "caught std::exception: "<< ex.what() << std::endl;
}
#ifdef _MSC_VER
system("pause");
#endif
return 0;
}
The problem is not related to initialization order, but rather to template instantiation.
Templated code is instantiated on demand, that is, the compiler will not instantiate any templated code that is not used in your program. In particular, in your case the static class member FactoryBase<>::factory_helper_ is not being instantiated and thus it does not exist in the final binary, it does not register itself... (you can check this with 'nm' from the gnu toolchain, that will show the list of symbols present in your executable)
Try changing the FactoryBase constructor to this:
template <class TClass, const char* ClassName>
class FactoryBase {
//...
FactoryBase(){
factory_helper_;
}
//...
};
This will force the compiler into actually instantiating the static member in the binary and you should be set. There is no need to create an empty method and calling it.
EDIT: As an answer to the comment, towards the end of paragraph §14.7.1[temp.inst]/1 in the current standard:
Unless a member of a class template or
a member template has been explicitly
instantiated or explicitly
specialized, the specialization of the
member is implicitly instantiated when
the specialization is referenced in a
context that requires the member
definition to exist; in particular,
the initialization (and any associated
side-effects) of a static data member
does not occur unless the static data
member is itself used in a way that
requires the definition of the static
data member to exist.
#define FACTORY_CLASS(classtype) \
class classtype; \
extern const char classtype##_name_[] = #classtype; \
template detail_::registerHelper_<FactoryBase<classtype,classtype##_name_>,classtype##_name_> FactoryBase<classtype,classtype##_name_>::factory_helper_; \
class classtype : FactoryBase<classtype,classtype##_name_>
explicitly instantiating factory_helper_ fixed the issue.