C++ - inherit from base class with member function as template argument - c++

I have this very simple class using CRTP:
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
class UpdatableBase {};
class MyClass : private UpdatableBase<MyClass> {
public:
void update() {
}
};
int main() {
return 0;
}
Which, when compiled with g++ test.cpp -std=c++14, gives this:
test.cpp:2:85: error: no member named 'update' in 'MyClass'
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
~~~~~~~~~~~~~^
test.cpp:5:25: note: in instantiation of default argument for 'UpdatableBase<MyClass>' required here
class MyClass : private UpdatableBase<MyClass> {
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Why does it say there's "no member named 'update' in 'MyClass'"? There very clearly is.

This is a very common problem with CRTP: the compiler instantiates the base class definition before it reads the derived class definition.
The work around is to only use the definition of the derived class inside base class member definition:
#include <type_traits>
template <typename DerivedType, class DelayedParameter = void>
class UpdatableBase {
public:
//definition of members of templates are instantiated when needed!
void update(){
if constexpr(std::is_same_v<DelayedParameter,void>)
static_cast<DerivedType>(this)->update();
else
(static_cast<DerivedType*>(this)->*DelayedParameter::value)();
}
};
class MyClassDelayedParameter;
class MyClass:public UpdatableBase<MyClass,MyClassDelayedParameter>
//the compiler only instantiate the definition of the base class:
//it will only instantiate the DECLARATION of the base class members.
{
public:
void update();
};
//Here MyClass is defined so we can access its member.
struct MyClassDelayedParameter:
std::integral_constant<void(MyClass::*)(),&MyClass::update>
{};
//UpdatableBase<...>::update DEFINITION is instantiated here. At this point
//of instantiation, MyClass and MyClassDelayedParameter are defined.
int main() {
MyClass a;
UpdatableBase<MyClass,MyClassDelayedParameter>& b=a;
b.update();
return 0;
}
DEMO

Related

template argument deduction failed when calling base function

The following C++ code produces compilation errors.
The compiler (gcc 5.2.0) complains that at line 15 it cannot find matching function for call to 'Derived::test_func()'; yet if test_func() is moved from Base to Derived, it compiles without error.
class Base {
public:
int test_func();
};
class Derived : public Base {
public:
template <typename T>
int test_func(T t);
};
template <typename T>
int Derived::test_func(T t)
{
test_func(); // line 15
return 0;
}
int Base::test_func()
{
return 0;
}
If the template function calls other functions in the Base class with different names (not the same name as the template function), as the following code shows, it also compiles fine.
class Base {
public:
int test_func_diff_name();
};
class Derived : public Base {
public:
template <typename T>
int test_func(T t);
};
template <typename T>
int Derived::test_func(T t)
{
test_func_diff_name();
return 0;
}
int Base::test_func_diff_name()
{
return 0;
}
Why is this? What is the constraints specified in C++ in calling base functions from templates? Can someone point me to some resources?
In C++, functions in derived classes which don't override functions in base classes but which have the same name hide all other functions with the same name in the base class.
It is usually preferable to give different functions different names.
If you really need it, you can call the base class' function by fully qualifying the name, like Base::test_func();
Or explicitly introduce the base class' names into the current class with using Base::test_func;

Inheriting base class with recursive template class [duplicate]

Let's look at this simple code sample including a base class and a class derived from Base, which needs the address of a base class member in its constructor.
#include <vector>
#include <inttypes.h>
#include <stdio.h>
class Base
{
protected:
std::vector<uint32_t> arr;
public:
Base(std::vector<uint32_t> arr_in): arr(arr_in) {}
};
class Derived: public Base
{
private:
uint32_t *parr;
public:
Derived(std::vector<uint32_t> arr_in): Base(arr_in)
{
parr = &arr[0];
}
uint32_t *get_parr();
};
uint32_t *Derived::get_parr(void)
{
return parr;
}
int main()
{
std::vector<uint32_t> myarr(3, 1);
Derived myderived(myarr);
printf("myderived.myarr adress = %p", myderived.get_parr());
}
Since the constructor of the derived class calls the base class constructor first and only then executes its code block, the members of the base class can already be accessed. So everything works fine.
Now I change the code sample so that my two classes are templates.
#include <vector>
#include <inttypes.h>
#include <stdio.h>
template<typename T>
class Base
{
protected:
std::vector<T> arr;
public:
Base(std::vector<T> arr_in): arr(arr_in) {}
};
template<typename T>
class Derived: public Base<T>
{
private:
T *parr;
public:
Derived(std::vector<T> arr_in): Base<T>(arr_in)
{
parr = &arr[0];
}
T *get_parr();
};
template<typename T>
T *Derived<T>::get_parr(void)
{
return parr;
}
int main()
{
std::vector<uint32_t> myarr(3, 1);
Derived<uint32_t> myderived(myarr);
printf("myderived.myarr adress = %p", myderived.get_parr() );
}
But this second sample gives me the following error message upon compiling:
class_temp.cpp: In constructor ‘Derived<T>::Derived(std::vector<T>)’:
class_temp.cpp:23:13: error: ‘arr’ was not declared in this scope
parr = &arr[0];
So why is it that in the second sample with template classes the derived class constructor doesn't know about the base class member?
Or am I doing something wrong here?
Thank you.
arr is a dependent name now. It depends on T. What if there is some T for which Base<T> is specialized to not have an arr? Specifically, from [temp.dep]:
In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined
during unqualified name lookup either at the point of definition of the class template or member or during
an instantiation of the class template or member.
Base<T> is a dependent base class - it depends on the template parameter T, so its scope is not examined during unqualified name lookup. The way around this is to use qualified name lookup. That is, either the class name:
parr = &Base<T>::arr[0];
or just with this:
parr = &this->arr[0];
In the second case, the Base is a template and someone might add specializations for the template, all with different member variables. The compiler cannot know until it sees what T is.
There might also be a global arr that could fit. You can help the compiler by using this->arr[0] to indicate that it always is a member variable.

Use template class before it has been specified

For some reason, I have to return value as an type-specified template class from itself. But the problem is that the template class inherit from a non-template class which have a method returns the value of type-specified template class.
It should be like this one:
class Base
{
// ...
_Int Foo() = 0;
};
template<typename T>
class Derived
: public Base
{
public:
// ...
_Int Foo() override
{
// ...
}
};
typedef Derived<int> _Int;
So my question is: Is there an way that can help me use a specified type of template class before it has been defined?
To declare a return type of a function, you don't need the definition of the type, only its declaration. Which means you can do this:
template <class T>
class Derived;
typedef Derived<int> _Int;
class Base
{
// ...
virtual _Int Foo() = 0;
};
template<typename T>
class Derived
: public Base
{
public:
// ...
_Int Foo() override
{
// ...
}
};
[Live example]
Two side notes, unrelated to the question:
Your code was missing virtual on the declaration of Foo.
Any name starting with an underscore followed by an uppercase letter is reserved for the C++ implementation (compiler and standard library) and must not be used in user code. You should change the name _Int to something else.
Names which contain two consecutive underscores are similarly reserved, and names which start with an underscore are reserved in global scope.
This is an instance of the curiously recurring template pattern, which can be used by taking the derived class as a template parameter to the base class:
template<typename Int>
class Base
{
// ...
virtual Int Foo() = 0;
};
and then passing it explicitly when inheriting:
template<typename T>
class Derived
: public Base<Derived<T>>
{
public:
// ...
Derived<T> Foo() override
{
// ...
}
};
Live demo

c++ template inheritance scheme

I wonder if the way I code this is correct. Can I create a template claas that inherits from a template class ? If I can, is the following code correct :
template<typename Type>
class A{
public:
A(){};
method_A(){//do whatever}
protected:
int a;
}
the second class is :
template<typename Type>
class B:public<Type> A {
public:
B(){};
method_B(){this->a=0; this->method_A();}
protected:
int b;
}
and my last class is :
class C:public<double> B{
public:
C(){};
method_C(){ b = 0; method_B();}
protected:
int c;
}
Why are the this-> mandatory in the class B but not in the class C ? And in general, should I always add this-> to reference arguments or methods that belong to the same class ?
This is specifically addressed in section 14.6.2p3 of the C++03 and C++11 standards:
In the definition of a class template or a member of a class template, if a base class of the class template depends on a template parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

C++ template method forward declaration

I'm having a little problem with my classes. I have two classes which both use template methods, therefore I have to put it in the header. Here is an example. I'd like it to compile properly without the "forward declaration incomplete" problem. I understand what is wrong but I can't figure how to correct this. Thank you guys.
class.h
class A;
class B;
class A
{
B *foo;
template <class T>
void func()
{
foo->fanc();
}
}
class B
{
A *foo;
void fanc();
template <class T>
void osef()
{
foo->func<int>();
}
}
You have a circular dependence. You can not declare an object of incomplete class. You can solve this by declaring either pointers or references to the incomplete class.
class A
{
B* foo;
or
class A
{
B& foo;
On the later case you have to initialize the reference with the member initialization list of the constructor.
If you are using pointer then you should move the definition of the memeber function after the definition of the incomplte class.
class A;
class B;
class A
{
B* foo;
template <class T>
void func();
};
class B
{
// ...
};
template <class T>
inline void A::func()
^^^^^^ // If you need to include the header in more than one source file.
{
foo->fanc();
}