"undefined reference" to static member of template class accessed from static method - c++

I have a static class method that needs access to a pointer MyTypePointer that therefore has to be declared static. Since it is a template class I have to put the methods inside the header file but I can't define MyTypePointer in the header.
So I get the "undefined Reference" error since MyTypePointer is not declared. How can I make this work / declare MyTypePointer.
myclass.h
template <typename A, typename B>
class PathfindingClass {
typedef std::vector<GenericEdgeClass<A, B>*> MyType;
static MyType *MyTypePointer;
};
template <typename A, B>
void MyClass<A, B>::MyMethod(int x, int y) {
//do something with MyTypePointer
}
Thank you very much.

It is a late answer for full reference, as this question is linked as a reference to another question.
A minimal broken example of a static field declared but not defined could be :
template<typename T>
class A
{
public:
static T val;
static void init()
{
val=0;
}
};
int main()
{
// A::init();
A<double>::init();
return 0;
}
The fix is just to define the static field after the class definition :
template<typename T>
class A
{
public:
static T val;
static void init()
{
val=0;
}
};
template<typename T> T A<T>::val; // only change here
int main()
{
// A::init();
A<double>::init();
return 0;
}

In the template definition, static MyType *MyTypePointer; declares an object. You still have to define it, outside the template class definition:
template <class A, class B>
typename PathfindingClass<A, B>::MyType*
PathfindingClass<A, B>::MyTypePointer;

You can still define the template member and explicitly instantiate it for all needed specializations. If you insist in having a state data member of a class template that's roughly what's needed.
Given that global variables share all sorts of problems, including dependency issues during initialization, you are much better off, wrapping you data member by a static member function:
template <typenane T>
class foo {
// ...
static X*& member() {
static X* rc = ...;
return rc;
}
};
The local variable is initialized the first time the function is called and a reference to it can safely be used. This approach also works for templates.
Note that I still recommend to avoid global variables! They cause many problems in the long-term and short-term benefit of using them is a huge debt which normally doesn't pay off.

Related

Making an optional template parameter a friend?

There is a post explaining that a template parameter can be declared as friend with the following syntax:
template <typename T>
class A {
friend T;
};
but what if in some scenarios A needs a fried and in others does not? Is it possible to make T an optional argument?
Is there a better solution than using some kind of FakeClass as T?
EDIT1: I found another solution:
class B {};
template <typename T>
class A {
friend T;
};
template <>
class A<void> {
};
int main()
{
A<B> a1;
A<void> a2;
return 0;
}
but what if A is a complicated class with 300 lines of code? Is there an alternative solution without template specialization?
I think befriending a dummy is the cleanest thing you can do, since you can't inherit or conditionally declare friends. You don't even need to create a new dummy type, since:
[class.friend§3]
If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored.
Which means that you can pretend to befriend int or even void and they'll play along just fine.
This advice is valid only within the limits of the C++ standard and is not intended as a real life guideline. The poster declines any and all responsibilities concerning the application of the advice.
Try this
template<typename... T>
class A {
private:
static const int i = 10;
public:
friend typename std::conditional<sizeof...(T) == 1, T..., void>::type;
};
class X {
public:
static const int a = A<X>::i;
};
class Y {
public:
static const int a = A<>::i; // error, A::i is private
};

Associating enums with template classes at compile time

I have a template class as below:
template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };
template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}
and I have an object that has a collection of these classes:
using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;
class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}
I want to know if it is possible to define an enum list:
enum TaskEnum
{
Etask1,
Etask2
};
and a function getTask such that in my app I can have:
int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}
I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?
Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.
First, to have error if type is not an exact match, you may use the following:
template <typename T>
class Task
{
public:
using type = typename T::type;
void bar(type a) { T::bar(a); }
template <typename U>
std::enable_if_t<!std::is_same<std::decay_t<U>, type>::value>
bar(U&&) = delete;
};
Then, with some helpers:
template <TaskEnum> struct TaskMap;
template <> struct TaskMap<Etask1> { using type = Task<TaskInfoX>; };
template <> struct TaskMap<Etask2> { using type = Task<TaskInfoY>; };
Your collection could be something like:
class TaskCollection
{
public:
Task<TaskInfoX> taskX;
Task<TaskInfoY> taskY;
template <TaskEnum E>
typename TaskMap<E>::type&
getTask();
};
template <>
Task<TaskInfoX>& TaskCollection::getTask<Etask1>() { return taskX; }
template <>
Task<TaskInfoY>& TaskCollection::getTask<Etask2>() { return taskY; }
With final usage:
collection.getTask<Etask1>().bar(testInt);
collection.getTask<Etask1>().bar(testDouble);//error:call to deleted member function 'bar'
collection.getTask<Etask2>().bar(testDouble);
Demo
You can always template a concrete class with primitives. So instead of:
using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;
you can just have
template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}
and then define a template function:
template<TaskEnum taskE>
Task<taskE>* getTask() {}
You will need to derive template class Task from a base class so you can put it in a map, and you should define a map
std::map<TaskEnum,TaskBase*> taskMap;
and in getTask you can just do a static cast:
static_cast<Task<taskE>* >(taskBasePtr);
I think std::tuple is what you need:
auto my_tuple = std::make_tuple(Task<TaskInfoX>(), Task<TaskInfoY>());
std::get<Task<TaskInfoX>>(my_tuple).bar(12);
// actually, this is not an error because double can be convert to int
std::get<Task<TaskInfoX>>(my_tuple).bar(12.323);
Given the way Task1 and Task2 are stored in your TaskCollection class, I cant see an obvious way to implement getTask as a template, but you can overload it.
class TaskCollection
{
//...
Task<TaskInfoX> GetTask(Task<TaskInfoX> task)
{
return Task1;
}
Task<TaskInfoY> GetTask(Task<TaskInfoY> task)
{
return Task2;
}
};
If your real case works in with double and int then you need to supress the conversion from double to int in order to achieve this compile-time error...
//collection.getTask(Task1)->bar(testDouble); //want compile error.
one way to do this is to declare but not define a template version of bar in your TaskInfo
template<typename A> struct TaskInfo
{
static void bar(A a){blah blah...}
template<typename T> static void bar(T a); // deliberately not defined
//...
};
you still define your existing bar function for the type you do want to handle, but now, in the case that you want to fail, the compiler will try to call the template version of bar (with T as a double) in preference to calling the int version with a conversion from double to int. The resulting error in VS2015 is
error LNK2019: unresolved external symbol "public: static void __thiscall C::bar(double)
but if no code tries to call it then it doesn't matter that it is not defined an there is no error.
(It wasn't clear to me what the question was regarding the enum)

How to access static of templated class from template?

I am trying to write a template using the CRTP pattern. What I would like is for the template to access a static const in the templated class.
My template look like this in it's own header:
template <class T> foo {
static const int readValue = T::value
}
And I inherit from the template like this (in another header file):
class fooImpl: foo<fooImpl> {
static const int value = 42;
}
However, clang complains:
No member named 'value' in 'fooImpl'
I think I get the chicken and egg problem here. The template does not know the definition of fooImpl, and hence, cannot know that it has the member value when it is instantiated.
But how do I work around it? Is there a way to get the compile time propagation of the const value into the instantiated template?
The foo<fooImpl> base class is instantiated in the base-class list but fooImpl is an incomplete type at that point, and foo::value has not been declared yet.
You can move the definition of the static member later:
template <class T> struct foo {
static const int readValue;
};
class fooImpl: foo<fooImpl> {
static const int value = 42;
};
template<class T> const int foo<T>::readValue = T::value;
However, this won't allow you to use readValue as a compile-time constant in the body of foo.

The initialization of a static instance of a nested class in template class

I'd like to do this:
template <typename T>
class S
{
...
class A
{
~A(){cout << "~A";}
};
static A obj;
};
template <typename T>
typename S<T>::A S<T>::obj;
int main()
{...}
But when the program starts, no static instance of the nested class A is created. "~A" is not printed then. What is the problem?
The answer depends on what is written in the '...' parts of your question. Here is a complete example that works using gcc 4.8.1; i.e. prints "Ahello~A"
If you comment out the code in main() the program produces nothing.
#include <iostream>
using namespace std;
template <typename T>
class S
{
public:
T m;
class A
{
public:
A() {cout << "A";}
void say() {cout << "hello";}
~A(){cout << "~A";}
};
static A obj;
};
template <typename T>
typename S<T>::A S<T>::obj;
int main() {
S<int>::obj.say();
}
If you do not use the static in your code, but you still want your static instance to be created, the answer given by jxh applies. In this (unlikely) case, you will have to explicitly instantiate the template class:
template class S<int>;
The static object in the template was not used
When you implicitly instantiate a template class, only the parts of the class that are used get instantiated. The standard makes a point to mention static data members in C++.11 §14.7.1¶8:
The implicit instantiation of a class template does not cause any static data members of that class to be implicitly instantiated.
Solution
Your will need non-template code that refers to the static object in some way, or you will need to explicitly instantiate the template.
Refer to the static object
Since obj is static and private to S, you need some public code in S that refers to this object. For example, a static method that returns it.
tempalte <typename T>
class S
{
//... define class A
static A obj;
public:
static A & get_obj () { return obj; }
};
template <typename T>
typename S<T>::A S<T>::obj;
Then, you can call this method from main() to implicitly instantiate obj.
int main()
{
get_obj();
}
Explicitly instantiate the template
Explicit instantiation of a template class will fully define it as if the template class had been written as a regular class. So, the static object will be created without need to refer to it implicitly.
template class S<int>;
Regarding the Singleton Pattern
Implicit instantiation behavior reduces bloat
If you are using your code of a singleton, then the behavior you observed is actually what you want. You only want your singleton objects created if they are actually used. This will prevent unused code from unnecessarily occupying resources in your program.
Prevent bloat for explicit instantiation
Since it is desirable to prevent run-time bloat of the program, then it is also desirable to do so even if the Singleton is explicitly instantiated. This is naturally accomplished by scoping the singleton instance inside the method that returns it.
template <typename T>
class S
{
class A
{
friend S;
~A(){std::cout << "~A\n";}
static A & getInstance () {
static A obj;
return obj;
}
};
public:
void foo () { A::getInstance(); }
};
When the static instance is scoped within the static method that returns it, there is no need to create a template definition of it outside of the class. The static instance only gets created at the moment getInstance() is called.

Accessing public static members of a templated class without instantiating the template?

I have a templated class and want to access a public static variable from outside it, but I can't figure out any way to do so without instantiating the template. This code:
template<class T>
class TemplatedClass {
public:
static const int static_member = 10;
};
...
int i = TemplatedClass::static_member;
Produces the following error: "'template class TemplatedClass' used without template parameters."
If I instantiate the class when accessing the variable:
int i = TemplatedClass<int>::static_member;
The error goes away. I would prefer not to have to instantiate a template in a context where it doesn't really make sense with a dummy type argument just to suppress an error. If I have to, what would be the best dummy type to use? I tried <> and <void>, but neither worked.
Can't be done, since specializations might override the value, i.e:
template<class T>
class TemplatedClass : public BaseClass
{
static const int value = 42;
};
template<>
class TemplatedClass<StarTrek>
{
static const int value = 47;
}
Thus you will get different values:
TemplatedClass<StarTrek>::value != TemplatedClass<void>::value
If the values are to be equal, I strongly suggest you add a non-template base class:
class BaseClass {
public:
static const int value = 42;
};
template<class T>
class TemplatedClass : public BaseClass
{
...
}
Instantiating or explicitly a dummy type (i.e. void) might work, but you might get compile errors depending on how you use your template parameter.
int x = TemplatedClass<void>::value;
So, please write code which show your intentions clearly, i.e. common values for all instantiations should not be in the type-dependent template class. If you can't have that, please explain what you're trying to do in more detail.
Using a dummy type might work for trivial classes, but not if things get more complex.
Let's imagine, that your class "continues" like this:
template<class T>
class TemplatedClass {
public:
static const int static_member = 10;
typedef typename std::enable_if< std::is_integral< T >::value >::type type;
};
This code tells us that T cannot be non-integral type.
Upd (thanks to jogojapan):
That's why in some cases you cannot use any type as a dummy one