How to access static of templated class from template? - c++

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.

Related

X is not a class template

I am trying to compile the below code, and I am getting the error as
"error: ‘MD5Sum’ is not a class template
template<> struct MD5Sum<::cv_bridge::CvImage>"
template<> struct MD5Sum<::cv_bridge::CvImage>
{
static const char* value() { return MD5Sum<::sensor_msgs::msg::Image>::value(); }
static const char* value(const ::cv_bridge::CvImage&) { return value(); }
static const uint64_t static_value1 = MD5Sum<::sensor_msgs::msg::Image>::static_value1;
static const uint64_t static_value2 = MD5Sum<::sensor_msgs::msg::Image>::static_value2;
// If the definition of sensor_msgs/Image changes, we'll get a compile error here.
ROS_STATIC_ASSERT(MD5Sum<::sensor_msgs::msg::Image>::static_value1 == 0x060021388200f6f0ULL);
ROS_STATIC_ASSERT(MD5Sum<::sensor_msgs::msg::Image>::static_value2 == 0xf447d0fcd9c64743ULL);
};
This seems to be template specialization. Does it means that template class should be present first before make template specialization out of it.
The class template MD5Sum needs to be declared before any of its specializations.
You either need to include the file where the template is declared, or declare it yourself.
You can use an empty definition (if you only want to call fully specialized versions) or the generic implementation you choose:
// add this before your specialization
template <class T> struct MD5Sum; // empty declaration
// or your default implementation
template <class T> struct MD5Sum {
...
};

Initializing a variable dependent on type in template parameter in C++

I have a class with a static const variable that I need to initialize differently depending on the variable type in the template parameter. Is there a way to do this without specialization?
In my header file I have:
template<class Item>
class CircularQueue {
public:
static const Item EMPTY_QUEUE;
...
Attempting to initialize it in the .cpp file:
template<typename Item> const Item CircularQueue<Item>::EMPTY_QUEUE = Item("-999");
I'd like it to initialize to -999 whether it's an int, double, or string. However, in the code above I get a "cast from 'const char' to 'int' loses precision [-fpermissive]" error.
Providing an example of using a separate helper class that can be specialized, instead of having to specialize this entire template class, since you mentioned you'd like to see an example of this approach.
Just declare a separate template class that sets the default value, and specialize it for std::string.
template<class Item> class defaultItem {
public:
static constexpr Item default_value() { return -999; }
};
template<> class defaultItem<std::string> {
public:
static constexpr const char *default_value() { return "-999"; }
};
You don't have to use the constexpr keyword, if your C++ compiler is not of a recent vintage. You can also define the same specialization for a const char *, rather than a std::string, if needed.
Then, your main class simply defines EMPTY_QUEUE as:
template<typename Item>
const Item CircularQueue<Item>::EMPTY_QUEUE =
defaultItem<Item>::default_value();

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

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.

Why does this code give the error, "template specialization requires 'template<>'"?

When I try to compile this with Clang
template<class T>
struct Field
{
char const *name;
Field(char const *name) : name(name) { }
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
class Class : public CRTP<Class> { };
Field<Class> const CRTP<Class>::_field("blah");
int main() { }
I get
error: template specialization requires 'template<>'
Field<Class> const CRTP<Class>::_field("blah");
~~~~~~~~~~~ ^
I don't understand the error at all. What is wrong with my definition of _field and how do I fix it?
(Note that the arguments to _field are not necessarily the same for all subclasses.)
For the compiler to identify this as a template specialization (e.g. to be able to check the syntax), you need the template keyword:
template<>
Field<Class> const CRTP<Class>::_field("blah");
Its brackets are empty as all template parameters are specialized, but you cannot just leave it away.
The error says exactly what is missing. template<> is missing before that line.
template<>
Field<Class> const CRTP<Class>::_field("blah");
Note, however, that your typing of Field<Class>, if unique, could be used to construct all instances of Field<Class> with a given string.
template<typename T>
struct field_trait;
template<class T>
struct Field
{
char const *name;
Field() : name(field_trait<T>::get_name()) {}
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
template<class Derived>
class CRTP<Derived>::_field;
class Class;
template<>
struct field_traits<Class> {
static const char* get_name() { return "blah"; }
};
class Class : public CRTP<Class> { };
int main() { }
which means that every instance of Field<Class> always has the name "blah".
One question I would have is, do you really need storage for said Field<Class> to actually have a pointer to a string, and if so does it need to be unique, and if so does it need to be "bare"? Because figuring out where the static instance exists is somewhat annoying.
Together with field_traits above:
template<class Derived>
class CRTP { static Field<Derived>& field() const { static Field<Derived> _field( field_traits<Derived>::get_name()); return _field; };
this moves the problem of "where is the _field stored" to being the compilers problem. And it is initialized by the contents of field_traits<T>::get_name().
A static data member must have both a declaration and a definition. If this was a plain class it would look like this:
// header:
class C {
static int i;
};
// source:
int C::i = 3;
Templates aren't ordinarily defined in source files, so the code would look something like this:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 3;
In your code, you don't have the definition of the static data member. That's okay if you don't use it. But the code that the compiler is complaining about defines a static data member for CRTP<Class>; that's a specialization (because it's not applicable to all instantiations of CRTP, just to this one), and the compiler is saying that you have to tell it that it's a specialization. So do as you're told:
template <>
Field<Class> const CRTP<Class>::_field("blah");
or, to write the non-specialized template version, use the usual template syntax:
template <class T>
Field<T> const CRTP<T>::_field("blah");

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