"Illegal reference to non-static member" when trying to implement CRTP - c++

I am trying to implement the curiously recurring template pattern (CRTP) to access a member variable of a child class from the parent class, but I am getting a compilation error saying I am illegally referencing a non-static member variable.
#include <iostream>
template <typename Child>
class Parent
{
public:
int get_value()
{
return Child::m_value;
}
virtual ~Parent() = default;
};
class Child : public Parent<Child>
{
int m_value = 42;
friend class Parent<Child>;
};
int main()
{
Child child;
std::cout << child.get_value() << std::endl;
}
Error:
illegal reference to non-static member 'Child::m_value'
How can I properly access the member variable of the child class from within the parent class?
Is CRTP even the best/cleanest approach here?

Here is the correct way to access members of a CRTP derived class.
template <typename Child>
class Parent
{
public:
int get_value()
{
// Do NOT use dynamic_cast<> here.
return static_cast<Child*>(this)->m_value;
}
~Parent() { /*...*/ }; // Note: a virtual destructor is not necessary,
// in any case, this is not the place to
// define it.
};
// A virtual destructor is not needed, unless you are planning to derive
// from ConcreteClass.
class ConcreteClass : public Parent<ConcreteClass>
{
friend class Parent<ConcreteClass>; // Needed if Parent needs access to
// private members of ConcreteClass
// If you plan to derive from ConcreteClass, this is where you need to declare
// the destructor as virtual. There is no ambiguity as to the base of
// ConcreteClass, so the static destructor of Parent<ConcreteClass> will
// always be called by the compiler when destoying a ConcreteClass object.
//
// Again: a virtual destructor at this stage is optional, and depends on
// your future plans for ConcreteClass.
public:
virtual ~ConcreteClass() {};
private:
int m_value;
};
// only ConcreteClass needs (optionally) a virtual destructor, and
// that's because your application will deal with ConcretClass objects
// and pointers, for example, the class below is totally unrelated to
// ConcreteClass, and no type-safe casting between the two is possible.
class SomeOtherClass : Parent<SomeOtherClass> { /* ... */ }
ConcreteClass obj1;
// The assignment below is no good, and leads to UB.
SomeOtherClass* p = reinterpret_cast<ConcreteClass*>(&obj1);
// This is also not possible, because the static_cast from
// Parent<UnrelatedClass>* to UnrelatedClass* will not compile.
// So, to keep your sanity, your application should never
// declare pointers to Parent<T>, hence there is never any
// need for a virtual destructor in Parent<>
class UnrelatedClass {/* ... */ };
auto obj2 = Parent<UnrelatedClass>{};
As the concrete type ConcreteClass and its relation to Parent is known ate compile-time, a static_cast is sufficient to convert this from Parent<ConcreteClass>* to a ConcreteClass*. This provides the same functionality as virtual functions without the overhead of a virtual function table, and indirect function calls.
[edit]
Just to be clear:
template <typename Child>
class Parent
{
public:
int get_value()
{
// the static cast below can compile if and only if
// Child and Parent<Child> are related. In the current
// scope, that's possible if and only if Parent<Child>
// is a base of Child, aka that the class aliased by Child
// was declared as:
// class X : public Parent<X> {};
//
// Note that it is important that the relation is declared
// as public, or static_cast<Child*>(this) will not compile.
//
// The static_cast<> will work correctly, even in the case of
// multiple inheritance. example:
//
// class A {];
// class B {};
// class C : public A
// , public Parent<C>
// , B
// {
// friend class Parent<C>;
// int m_value;
// };
//
// Will compile and run just fine.
return static_cast<Child*>(this)->m_value;
}
};
[edit]
If your class hierarchy gets a bit more complex, the dispatching of functions will look like this:
template <typename T>
class A
{
public:
int get_value()
{
return static_cast<T*>(this)->get_value_impl();
}
int get_area()
{
return static_cast<T*>(this)->get_area_impl();
}
};
template <typename T>
class B : public A<T>
{
friend A<T>;
protected:
int get_value_impl()
{
return value_;
}
int get_area_impl()
{
return value_ * value_;
}
private:
int value_;
};
template <typename T>
class C : public B<T>
{
// you must declare all bases in the hierarchy as friends.
friend A<T>;
friend B<T>;
protected:
// here, a call to C<T>::get_value_impl()
// will effetively call B<T>::get_value_impl(),
// as per usual rules.
// if you need to call functions from B, use the usual
// syntax
int get_area_impl()
{
return 2 * B<T>::get_value_impl();
}
};

Related

C++ SafeSingleton 3 level inheritance

I have a templated SafeSingleton class, Base class which is derived from SafeSingleton and implements some base methods. I want to have class that is derived from Base and can be accessed via instance() method of SafeSingleton. The problem is that when I am trying to access Derived::instance() it returns the pointer to a Base class and the compiler doesn't know anything about methods of derived class. What should I do to make below code work.
template<class T>
class SingleTon {
public:
static T* instance()
{
return holder().instance;
}
protected:
template<class I>
struct Holder
{
Holder() : instance(new I())
{
}
I* instance;
};
static Holder<T> &holder()
{
static Holder<T> holder;
return holder;
}
};
// Hopefully issue is here, I am never creating SingleTon<Derived>, but how can it be done?
class Base : public SingleTon<Base> {
public:
Base() = default;
void printBase() {
std::cout << "Base";
}
};
class Derived : public Base {
public:
Derived() = default;
void printDerived() {
std::cout << "Derived";
}
};
int main()
{
Derived::instance()->printBase();
Derived::instance()->printDerived(); // Here is the error
//Error: main.cpp:57:26: error: ‘class Base’ has no member named ‘printDerived’
//57 | Derived::instance()->printDerived();
return 0;
}
template<class D>
class Base : public SingleTon<D> {
and
class Derived : public Base <Derived>
and ... done?
If you want to put Base's non-Ddependent methods in a cpp file, you'll have to get fancy. Have BaseImp that does not derive from SingleTon, put code there. Have Base<D> derive from it and write forwarding glue to it BaseImpl. But you probably don't need this.

Base class needs derived class attributes

I'm currently creating a game in SFML. To put it simply, I have an Object class that has all the common features for all objects. Player and Enemy class inherit from Object. There is also an ObjectManager that has a list of all Object and updates and draws them etc.
// using SFML shapes
class Player : public Object
{
public:
sf::CircleShape playerShape;
};
class Enemy : public Object
{
public:
sf::Sprite enemyShape;
};
class Object
{
public:
void move(...) { // move the shape, but the shapes are only found in the derived }
void draw(...) { // same problem as above, etc... }
};
class ObjectManager
{
private:
std::map<int, std::shared_ptr<Object>> gameObjectMap; // id, object
public:
void updateAll(...) {
// loop over all objects and update them
for (auto itr = gameObjectMap.begin(); itr != gameObjectMap.end(); ++itr) {
itr->second->move(...);
itr->second->draw(...);
}
}
};
Above you can see that Object::move() cannot be used because Object does not know about the SFML shapes in the derived classes. Therefore you could make the function Object::move() pure virtual but this means that you'd need to write implementations in the derived classes for any shape specific function that you need to use, this also includes any attributes about the shape, such as its position sf::Shape::getPosition(), etc. So this approach does not scale well.
An alternative that I thought about would be to have the Object class as a class template
template<typename T>
class Object
{
protected:
T object;
public:
void move(...) { object.move(...); }
T getObject() { return object; }
};
class Player : public Object<sf::CircleShape>
{ ... };
However this means that ObjectManager now must hold class templates Object in the map, and I'm not sure how that would work?
What's the best way to handle this situation?
how about this:
class Object
{
virtual auto move() -> void = 0;
};
template <class Shape>
class Shape_object : Object
{
Shape shape;
auto move() -> void override
{
// implementation
}
};
// you can have specializations for each shape type
// if you can't use the generic one
class Player : public Shape_object<sf::CircleShape>
{
//
};
class Enemy : public Shape_object<sf::Sprite>
{
//
};
template<typename T>
class Object {
// ...
};
If you really consider using a template class, you should use the CRTP (aka Static Polymorphism):
template<typename Derived>
class Object {
public:
/* virtual */ auto move() -> void {
// ^^^^^^^^^^^^^ Hooray! No more vtable \o/ (but wait ...)
static_cast<Derived*>(this)->doMove(); // Fails to compile, if
// Derived isn't inheriting from
// Object<Derived> or Derived
// doesn't implement doMove().
};
};
The drawback of that pattern is that everything must be resolved at compile time. Runtime injections of interface implementations (e.g. via plugins) won't work with that pattern well.
You could leave a thin layer though to make virtual destruction and such work properly:
struct ObjectBase {
virtual ~ObjectBase() {} // << that's enough
};
template<typename Derived>
class Object : public ObjectBase {
// ...
}

Infer 'this' pointer type when called from derived class?

I have a method in a baseclass that needs the type passed to it for some type-related operations (lookup, size, and some method invocation). Currently it looks like this:
class base
{
template<typename T>
void BindType( T * t ); // do something with the type
};
class derived : public base
{
void foo() { do_some_work BindType( this ); }
};
class derivedOther : public base
{
void bar() { do_different_work... BindType( this ); }
};
However, I wonder if there's a way to get the caller's type without having to pass this so that my callpoint code becomes:
class derived : public base
{
void foo() { BindType(); }
};
Without the explicit this pointer. I know that I could supply the template parameters explicitly as BindType<derived>(), but is there a way to somehow extract the type of the caller in some other way?
There's no magical way to get the caller's type, but you can use CRTP (as a comment mentions) in order to automate this behavior, at the cost of a bit of code complexity:
class base
{
template<typename T>
void BindType(); // do something with the type
};
template <class T>
class crtper : base
{
void BindDerived { BindType<T>(); }
}
class derived : public crtper<derived>
{
void foo() { do_some_work BindDerived(); }
};
class derivedOther : public crtper<derivedOther>
{
void bar() { do_different_work... BindDerived(); }
};
Edit: I should mention, I would kind have expected that foo would be a virtual function, defined without implementation in base. That way you would be able to trigger the action directly from the interface. Although maybe you have that in your real code, but not in your example. In any case, this solution is perfectly compatible with this.
Edit2: After question edit, edited to clarify that solution still applies.
If you want to avoid BindType<derived>(), consider (a bit verbose, I agree) BindType<std::remove_reference<decltype(*this)>::type>(); to avoid passing a parameter. It gets resolved at compile-time and avoids run-time penalties.
class base
{
protected:
template<typename T>
void BindType() { cout << typeid(T).name() << endl; } // do something with the type
};
class derived : public base
{
public:
void foo()
{
BindType<std::remove_reference<decltype(*this)>::type>();
}
};
It will not work as you expect
The result of foo() might be different of what you expect:
class derived : public base // <= YOU ARE IN CLASS DERIVED
{
public:
void foo() { BindType( this ); } // <= SO this IS OF TYPE POINTER TO DERIVED
};
The template paramter is deducted at compile time, so that it will be derived*. If you would call foo() from a class derived_once_more derived from derived, it would still use the type derived*.
Online demo
But you can get rid of the dummy parameter*
You may use decltype(this) to represent the typename of a variable. It's still defined at compile time:
class base
{
public:
template<typename T>
void BindType( )
{
cout << typeid(T*).name()<<endl; // just to show the type
}
virtual ~base() {}; // for typeid() to work
};
class derived : public base
{
public:
void foo() { BindType<decltype(this)>( ); }
};
Online demo
Edit: other alternatives
As template parameters need to be provided at compile-time and not a run time, you can use:
template parameter deduction (your first code snippet)
decltype (see above)
if you intend to add this in all the derived classes you could use a macro to get it done, using one of the above mentionned solution
you could use the CRTP pattern (already explained in another answer).
A possible solution that avoids the intermediate class of the CRTP follows:
class base {
using func_t = void(*)(void *);
template<typename T>
static void proto(void *ptr) {
T *t = static_cast<T*>(ptr);
(void)t;
// do whatever you want...
}
protected:
inline void bindType() {
func(this);
}
public:
template<typename T>
base(T *): func{&proto<T>} {}
private:
func_t func;
};
struct derived1: base {
derived1(): base{this} {}
void foo() {
// ...
bindType();
}
};
struct derived2: base {
derived2(): base{this} {}
void bar() {
// ...
bindType();
}
};
int main() {
derived1 d1;
d1.foo();
derived2 d2;
d2.bar();
}
The basic idea is to exploit the fact that the this pointers in the constructor of the derived classes are of the desired types.
They can be passed as a parameter of the constructor of the base class and used to specialize a function template that do the dirty job behind the hood.
The type of the derived class is actually erased in the base class once the constructor returns. Anyway, the specialization of proto contains that information and it can cast the this pointer of the base class to the right type.
This works fine as long as there are few functions to be specialized.
In this case there is only one function, so it applies to the problem pretty well.
You can add a static_assert to add a constraint on T, as an example:
template<typename T>
base(T *t): func{&proto<T>} {
static_assert(std::is_base_of<base, T>::value, "!");
}
It requires to include the <type_traits> header.

C++: Calling derived specialised virtual functions within a base template class

Let's say I have the following template class:
template<typename T>
class A
{
public:
// Lots of functions...
void someFunc(T obj)
{
// T must implement this function in order to be usable within class A.
obj.interfaceFunc();
}
};
This works fine, as the object I will use with the template class implements interfaceFunc().
However, if I pass a pointer to the template class then the compilation fails because the dereference syntax is incorrect. Because the template class contains a lot of other functions that I don't want to copy/paste into another partial specialisation if I can possibly help it, I have changed my class definition as follows:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
However, when virtualHelperFunction() is called, on an instance of B but when inside the someFunc() function of the parent A, it hits the assertion error.:
B<SomeObject> instance;
instance.someFunc(SomeObject()); // Assertion failure.
I've tried messing around with function pointers to solve this but I'm still fairly new to them, and the non-static pointer syntax confused me a bit. I'm assuming one could define a member pointer to the virtualHelperFunction() which is set to point to the base class version in A's constructor, but which is then overwritten in B's constructor to point to B's function. If so, would anyone be able to demonstrate the correct syntax to do this?
Thanks.
EDIT: If context is needed, the template class is an octree node which stores a hash table of type T. The interface function required is that the object can return a bounding box, in order for recursive insertion to function depending on whether the object's bounds intersect with the tree node's bounds.
https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.h
https://github.com/x6herbius/crowbar/blob/qt3d-experimental/Modules/Octree/inc/worldculltreenode.tcc
This seems way too complicated. Why specialize the entire class if you just need one tiny bit specialized? All you need is a small utility that says "dereference this if it's a pointer, otherwise leave it alone". It could look like this:
template <typename T>
T& deref_if_pointer(T& t) { return t; }
template <typename T>
T& deref_if_pointer(T* t) { return *t; }
// ...
void someFunc(T obj) {
deref_if_pointer(obj).interfaceFunc();
}
You can easily extend deref_if_pointer to various smart pointers as well; just add another overload.
I'm not really sure what it is that you want to accomplish, so I'll have to guess. In what way does the following not satisfy your problem?
class A
{
public:
// Lots of functions...
void someFunc(T* obj)
{
// T must implement this function in order to be usable within class A.
obj->interfaceFunc();
}
void someFunc(T obj)
{
// T must implement this function in order to be usable within class A.
obj.interfaceFunc();
}
};
If you want to do it that way, then you need to take a reference instead of a pointer in the first partial specialization:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Partial specialisation 1
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T& obj)
{
obj.interfaceFunc();
}
};
// Partial specialisation 2
template<typename T*>
class B : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
Your code doesn't compile. template<typename T*> is illegal and you do not have any partial specializations as you claim.
This works:
template<typename T>
class A
{
public:
// Lots of functions...
virtual void virtualHelperFunction(T* obj)
{
// We should never be here in the base class.
assert(false);
}
void someFunc(T obj)
{
// Call the virtual function.
virtualHelperFunction(&obj);
}
};
// Unspecialized template
template<typename T>
class B : public A<T>
{
public:
// ...
virtual void virtualHelperFunction(T* obj)
{
obj->interfaceFunc();
}
};
// Partial specialisation
template<typename T>
class B<T*> : public A<T*>
{
public:
// ...
virtual void virtualHelperFunction(T** obj)
{
(*obj)->interfaceFunc();
}
};
int main() {
B<SomeObject> instance1;
instance1.someFunc(SomeObject());
B<SomeObject*> instance2;
SomeObject x;
instance2.someFunc(&x);
}

No matching function call to T::T() in class template

I'm trying to write a generic template class, but I keep getting this error when I try to implement it:
no matching function for call to type_impl::type_impl()
where type_impl is the type I'm trying to use the class with.
Here's my code:
class BaseClass {
protected:
// Some data
public:
BaseClass(){
// Assign to data
};
};
template <class T>
class HigherClass : BaseClass {
private:
T data;
public:
// Compiler error is here.
HigherClass(){};
// Other functions interacting with data
};
class Bar {
private:
// Some data
public:
Bar(/* Some arguments*/) {
// Assign some arguments to data
};
};
// Implementation
HigherClass<Bar> foo() {
HigherClass<Bar> newFoo;
// Do something to newFoo
return newFoo;
};
The problem is that, since you have provided a nondefault constructor for Bar, the compiler no longer provides a default constructor, and this is required in your code:
HigherClass(){}; // will init data using T()
So provide a default constructor for Bar. For example:
class Bar {
public:
Bar() = default; // or code your own implementation
Bar(/* Some arguments*/) { ... }
};