Inheriting base class with recursive template class [duplicate] - c++

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.

Related

Static Assert Template inherits from class

How can I guarantee that T inherits from Base<T>?
So I have
#include <type_traits>
template <typename T>
class Base {
public:
static_assert(std::is_convertible<T*, Base<T>*>::value, "Class must inherit Base as public");
};
class DerivedWithPublic : public Base<DerivedWithPublic> { };
int main() {
DerivedWithPublic p;
static_assert(std::is_convertible<DerivedWithPublic*, Base<DerivedWithPublic>*>::value, "Class must inherit Base as public");
}
The static_assert in main is true. However the one inside of base is false! So the compiler fails. I want the assertions to be within the class itself? Firstly, i dont understand why one passes and the other one doesn't. Secondly, I need a solution. Thanks in advance.
Base<DerivedWithPublic> is instantiated at the point where it appears in DerivedWithPublic's list of base, at which time DerivedWithPublic is not yet complete type since its declaration hasn't been parsed yet. You can delay assertion until it is completed. One possible solution for this problem is to put the assertion in a member function of Base that you know must be instantiated, for example the destructor.
Live example
#include <type_traits>
template <typename T>
class Base {
public:
~Base() {
static_assert(std::is_convertible<T*, Base<T>*>::value, "Class must inherit Base as public");
}
};
class DerivedWithPublic : public Base<DerivedWithPublic> { };
int main() {
}

How do I properly derive from a nested struct?

I have an abstract (templated) class that I want to have its own return type InferenceData.
template <typename StateType>
class Model {
public:
struct InferenceData;
virtual InferenceData inference () = 0;
};
Now below is an attempt to derive from it
template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
// struct InferenceData {};
typename MonteCarlo::InferenceData inference () {
typename MonteCarlo::InferenceData x;
return x;
}
};
This works, but only because the definition of MonteCarlo::InferenceData is commented out. If it is not commented, I get invalid covariant return type error. I want each ModelDerivation<StateType>::InferenceData
to be its own type and have its own implementation as a struct. How do I achieve this?
You cannot change the return type of a derived virtual method.
This is why your compilation failed when you try to return your derived InferenceData from MonteCarlo::inference().
In order to achieve what you need, you need to use a polymorphic return type, which requires pointer/reference semantics.
For this your derived InferenceData will have to inherit the base InferenceData, and inference() should return a pointer/reference to the base InferenceData.
One way to do it is with a smart pointer - e.g. a std::unique_ptr - see the code below:
#include <memory>
template <typename StateType>
class Model {
public:
struct InferenceData {};
virtual std::unique_ptr<InferenceData> inference() = 0;
};
template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
struct InferenceDataSpecific : public Model<StateType>::InferenceData {};
virtual std::unique_ptr<Model::InferenceData> inference() {
return std::make_unique<InferenceDataSpecific>();
}
};
int main()
{
MonteCarlo<int> m;
auto d = m.inference();
return 0;
}
Note: if you need to share the data, you can use a std::shared_ptr.
You have to make the return type part of the template arguments:
template <typename StateType, typename InferenceData>
class Model {
public:
virtual InferenceData inference () = 0;
};
Then you can set the return type when you derive from it.
You can actually have your MonteCarlo::inference return a pointer (or reference) to a MonteCarlo::InferenceData, as long as you do things correctly otherwise. A simple version looks like this:
#include <memory>
#include <iostream>
template <typename StateType>
class Model {
public:
// base return type:
struct InferenceData { };
virtual InferenceData *inference() = 0;
};
template <typename StateType>
class MonteCarlo : public Model<StateType> {
public:
// derived return type must be derived from base return type:
struct InferenceData : public ::Model<StateType>::InferenceData { };
InferenceData *inference() { return new InferenceData; }
};
int main() {
MonteCarlo<int> mci;
auto v = mci.inference();
}
This a a covariant return type (as the compiler alluded to in its error message). There are a couple of points to keep in mind here though:
The return type really does have to be covariant. That is, the base class function has to be declared to return a pointer/reference to some base class, and the derived function has to return a pointer/reference to a type derived from that that the base function returns.
A unique_ptr<Derived> allows implicit conversion to unique_ptr<Base>, assuming Derived is derived from Base, but a unique_ptr<Derived> still isn't actually derived from unique_ptr<Base>, so you can't use (most typical) smart pointers for covariant returns.
For the moment, I've used new to create the returned object. That's pretty common when dealing with derivation and such, but it can be avoided if necessary. Doing that can get non-trivial in itself, depending on your needs. In a really simple case, define a static object of the correct type, and return a pointer to it (but that leads to problems if you do multi-threading).

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

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

C++ CRTP And Incomplete Class Definition

Is referring to derived class fields allowed in base definition when using CRTP?
template<typename T>
class Base
{
public:
constexpr int IntInDerived = T::SomeInt; // <--- Is This Valid
using TypeInDerived = typename T::SomeType; // <--- Is This Valid
};
class Derived : public Base<Derived>
{
public:
constexpr int SomeInt = 10;
using SomeType = float;
};
I'm not sure because even though T::SomeInt and T::SomeType are dependent names, at moment Base is instantiated Derived is considered an incomplete type.
Apparently these are not valid when placed inside class definition block like in the question. However accessing T's members inside a method would be valid since methods are separately instantiated later.

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.