Suppose I have such a template class:
template <class T>
class Queue
{
public:
static int Size;
};
template <class T> int Queue<T>::Size = 0;
And I export a function in D.dll use Queue as an parameter:
void ChangeQueueSize(Queue<int>& q)
{
q.Size = 100;
}
And then I use this exported function in an A.exe:
Queue<int> q;
q.Size = 10;
ChangeQueueSize(q);
int updatedSize = q.Size;
Since the Queue class is generated from the class template in 2 projects, there are actually 2 copies of the code, as well as the static data member.
So calling ChangeQueueSize won't really change queue size here, it just update another class's static member, which happens to be have the same class name.
What can we do to solve this problem?
Is weak symbol in gcc capable of address this?
Thanks so much.
You cannot put templates in a library in the way you might think. You can only put actual, instantiated class definitions in a library.
Templates are essentially a code generation tool, and you can only put generated code into the library.
You might want to use explicit template instantiation to make the compiler generate the code, and take the static member definition out of the header:
// Header, shipped to clients
template <class T>
class Queue
{
public:
static int Size;
};
// Library source code:
template <typename T> int Queue<T>::size = 0;
template class Queue<int>;
Now compile the source file into the library; this will contain the instance of the static member variable Queue<int>::size.
Note that your consumers will only be able to use instances of your class with T = int since they don't have access to the static member otherwise (i.e. they'd have to provide their own).
Related
I'm designing a wrapper over various computational functionality. Some of the underlying backends require some init functions to be called before any other API calls are made. I could use some static variable that is initialized before main, and wrap it in some function as described here so that I can catch any errors produced during initialization.
I wonder if there is a better way to handle this. Note that there will never be an instance of the class template, as everything is either a typedef or static member.
To address the problem of initializing the API only for some specializations, and of initializing it only once, I'd do something like this:
#include <iostream>
template <typename T>
struct Wrapper
{
// class who will be statically instantiated
struct CtorClass
{
CtorClass()
{
std::cout << "Init\n";
}
};
static CtorClass static_ctor;
static void compute1(){}
static void compute2(){}
};
// definition for template static member cons
template <typename T>
typename Wrapper<T>::CtorClass Wrapper<T>::static_ctor;
struct NeedInit{};
// you will have to use static_ctor in every funcition of the
template <>
void Wrapper<NeedInit>::compute1()
{
static_ctor;
}
template <>
void Wrapper<NeedInit>::compute2()
{
static_ctor;
}
int main()
{
Wrapper<int>::compute1();
Wrapper<int>::compute2();
Wrapper<NeedInit>::compute1();
Wrapper<NeedInit>::compute2();
}
Sadly, this way you have to use static_ctor in every function specialization that belongs to a Wrapper<NeedInit> class. But you wouldn't need to check for the initialization to have already been called.
Then, you could catch errors like you said.
I have the following code (it's on ideone.com):
template<class T>
class CMemoryPool
{
public:
CMemoryPool(int param1)
: stuff(param1)
{}
private:
T stuff;
};
template<class T>
class CList
{
public:
struct Entry
{
T data;
};
static CMemoryPool<Entry> s_pool;
};
template<class T>
CList<T>::CMemoryPool<CList<T>::Entry>::s_pool(1);
int main()
{
CList<int> list;
}
I can't seem to get the initialization of s_pool outside of the class to compile. Can anyone help me figure out how to make this work? Note I'm using C++03 only.
I think that you forgot how initializing a static data member works in general:
struct Data { int i; };
struct Holder { static Data StaticMember; };
Data Holder::StaticMember = { 1 };
^ ^~~~~~~~~~~~~~~~~~~~ static member qualified name
\~~~ static member type
If you look at your declaration, it is striking that you forgot one of the two above:
// Only a single element: there should be a type and a name
template<class T>
CList<T>::template CMemoryPool<typename CList<T>::Entry>::s_pool(1);
// Two elements
template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);
^ ^~~~~~~~~~~~~~~~ name
\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ type
Once corrected it just works
EDIT:
I was under the impression that:
You must explicitly give value to the static value for each instantiation of the template:
CList<int>::CMemoryPool<CList<int>::Entry>::s_pool(1);
must be somewhere in your *.C files...
Alternatively, use a static local variable in a method of the table used to get the value.
But after playing a bit, this seems to compile in ideone
template<class T>
CMemoryPool<typename CList<T>::Entry> CList<T>::s_pool(1);
I still recommend #FredOverflow solution as it protects your from static initialization problems
Static data members inside class templates are somewhat of a pain to initialize. I suggest a factory function instead. Then you don't need to worry about defining the variable somewhere else.
Just rewrite the line
static CMemoryPool<Entry> s_pool;
to
static CMemoryPool<Entry>& s_pool()
{
static CMemoryPool<Entry> foobar;
return foobar;
}
And then use s_pool() instead s_pool everywhere. You get lazy initialization as a benefit.
I'm trying to build a wrapper around a managed class so I can call it from native code.
Here is the managed function :
void MyManagedFunction(MyStruct iStruct)
{
// Code according to what are the types of the 2 MyStruct members
}
struct MyStruct
{
public MyStruct(Object iValue1, Object iValue2) : this()
{
Value1 = iValue1; // Often contains DateTime::Now
Value2 = iValue2;
}
public Object Value1;
public Object Value2;
}
In my case, Value1 will almost always be System::DateTime::Now and the Value2 will almost always be a common data type (int, double, float, string, bool). I thought of making two templated function in the wrapper.
In the wrapper's .h I have the following :
#ifdef MYWRAPPER_EXPORTS
# define MYWRAPPER __declspec(dllexport)
#else
# define MYWRAPPER __declspec(dllimport)
#endif
class MYWRAPPER MyWrapper
{
public:
MyWrapper();
~MyWrapper();
template <class T> void MyNativeFunction(T iParam1)
{
MyStruct^ wStruct = gcnew MyStruct(System::DateTime::Now, iParam1);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
template <class T, class W> void MyNativeFunction(T iParam1, W iParam2)
{
MyStruct^ wStruct = gcnew MyStruct(iParam1, iParam2);
//The class containing the managed function is a singleton
MyManagedClass::Instance->MyManagedFunction(wStruct);
}
};
This wrapper compiled without problem. The problem obviously occurred when I included the .h in the purely native code. Since I can't hide the content of the templated function, I have managed stuff visible on the native side which prevent the native code from compiling.
I was wondering if there was a workaround in order to achieve this. I don't mind if I'm limited into using only primitive types as parameters for the function. The best thing is if I was able to simply hide the content of the templated function in the native code so it only knows about the signature
Here's what I've tried/considered so far :
Converting the parameters to void* and call a function in which would call the managed one. By doing so, I can't cast the void* back to an object since I lose its type and using typeid to get the 'T' or 'W' type doesn't help since it vary from a compiler to another.
Overloading the function for every types I want to use. This is what I'll most likely use if I doesn't find a better solution. The problem is it means alot of overloading (especially for the 2 parameters function considering the number of combination)
If you know all the types your template will take, you can force instantiate it with those variables and thus put the code for the template functions in the source file instead of a header.
You can look at the example provided in Storing C++ template function definitions in a .CPP file
As he says you can do as below (copy-paste alert):
.h file
class foo
{
public:
template <typename T>
void do(const T& t);
};
.cpp file
template <typename T>
void foo::do(const T& t)
{
// Do something with t
}
template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
I have a problem regarding 'static const' member initialization. In a templated class I define a const member and initialize it outside the class.
When I include the .h file where this class is implemented in multiple .cpp files, I get an LNK2005 error (I'm using VS2010) that says the constant is already defined.
// List.hpp
template <class T>
class List {
static const double TRIM_THRESHOLD;
};
template <class T>
const double List<T>::TRIM_THRESHOLD = 0.8;
I tried putting the member initialization in a .cpp file, but then I get a linker error saying that the constant is not defined at all. If the list is not templated and I put the initialization in a .cpp file, all is fine.
Is there any solution for this situation? I have #ifdef/define clauses around the file already, and it's definitely not a solution.
You should define the constant in a source file not a header (so it only gets defined once) since this is a template which you need to keep in the header(and all instances have the same value) you can use a common base class.
class ListBase {
protected:
ListBase() {} // use only as base
~ListBase() { } // prevent deletion from outside
static const double TRIM_THRESHOLD;
};
template <class T>
class List : ListBase {
};
// in source file
double ListBase::TRIM_THRESHOLD = 0.8;
Another option is to have it as a static function:
static double trim_threashold() { return 0.8; }
Edit: If your compiler supports C++11 you make your static method a constexpr function so that it has all the optimization opportunities that using the value directly has.
So i am trying to export somethings in a project to DLL. Anyways a few of the projects use a singleton class very heavily.
template <typename T>
class DLL_IMP VA_Singleton {
protected:
VA_Singleton () {};
~VA_Singleton () {};
public:
static T *Get(){
return (static_cast<T*> (a_singleton));
}
static void Delete(){
if(a_singleton == NULL) {
delete a_singleton;
}
}
static void Create(){
a_singleton = GetInstance();
if(a_singleton == NULL){
a_singleton = new T;
}
}
private:
static T *a_singleton;
};
template <typename T> T *VA_Singleton<T>::a_singleton = NULL;
I got the export working fine, but when it comes to importing it states this:
template <typename T> T *VA_Singleton<T>::a_singleton = NULL;
Does not work with DLLImport. This is the first time ive ever really worked with DLL's in a work enviroment. Does anyone have any ideas?
Please see Multiple Singleton Instances
You will have to ensure that your template instantiation is done in one compilation unit, and you will have to move the pointer = NULL initialization to the CPP file. In other DLLs, you'll have to use extern templates.
Edit:
If you are stuck with getting templated singletons to work over multiple DLLs, you could also define a short wrapper function that returns your singleton instance so that the template instantiation is done in one compilation unit only.
Example:
template class Singleton<T>;
__declspec(dllexport/dllimport) T& getInstanceForMyType();
// in the cpp file:
T& getInstanceForMyType()
{
return Singleton<MyType>::getInstance();
}