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.
Related
I'm trying to figure out, how can I inherit from template class to template class. The problem is: I can't use protected members of Parent class.
Example:
template <class N>
class Parent {
protected:
N member;
public:
Parent(N aa){
member = aa;
}
};
class Child1: public Parent<int>{
public:
Child1(int a): Parent<int>(a) {
member += 1; // works
}
};
template<class Q>
class Child2: public Parent<Q>{
public:
Child2(int a): Parent<Q>(a) {
member += 1; // does not work (use of undeclared identifier)
}
};
How can I use "member" in the Child2 class?
Thanks for your time
You need to use this->member or Parent<Q>::member.
In the second case, member is a "dependent name" because the existence of member from the base class template Parent<Q> depends on the type of class Q in the template, whereas in the first example there is no dependent type, the compiler can statically analyze that Parent<int> contains member.
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
Is it possible to declare a templated class in C++ along with the classes it inherits from? Basically I want to give the compiler a hint, that my templated class will always inherit another at declaration time.
Maybe some code will clear up why this is a problem for me:
template<typename T>
class GrandparentClass
{
public:
T grandparentMember;
};
//this needs to be only a declaration, since I do not want classes of ParentClass with random T
template<typename T>
class ParentClass : public GrandparentClass<T>
{
};
// this does not work:
//template<typename T>
//class ParentClass : public GrandparentClass<T>;
// this does not either, because then the child class cannot access the variable from the grandparent class
//template<typename T>
//class ParentClass;
template<>
class ParentClass<int> : public GrandparentClass<int>
{
public:
ParentClass()
{
grandparentMember = 5;
}
};
template <typename T>
class ChildClass : public ParentClass<T>
{
public:
void foo()
{
std::cout << grandparentMember << "\n";
}
};
Also, I cannot use C++ 11.
EDIT:
I found an easy way out of this:
template<typename T>
class ParentClass : public GrandparentClass<T>
{
public:
ParentClass() { ParentClass::CompilerError(); };
};
Just do not define CompilerError() method in the class and everything's fine.
A class declaration is only really useful for non-value variable declarations, like pointers and references. You can't access the class members or even instantiate it, though. Even if you knew that a declared class inherits from some other one, you still wouldn't necessarily be able to utilize that information in any way.
As such, it's only important for the compiler to know what the class inherits from once it learns its full definition.
After clarification in comments: if you want to prevent instantiation of a class template with some types, its definition is the place to do it. A simple static_assert inside the class body will do the trick; Boost.StaticAssert or older SFINAE tricks will do the job for pre-C++11 code.
If you are happy with delaying the error to link-time, rather than compile time, you can declare all the member functions of parent in parent.h, provide definitions in parent.cpp, and explicitly instantiate the finite list of classes that you want.
Parent.h
template<typename T>
class ParentClass : public GrandparentClass<T>
{
ParentClass();
};
class ParentClass<int>;
class ParentClass<long int>; // or whatever
Parent.cpp
template <typename T>
ParentClass::ParentClass() : grandparentMember(5) {}
I have the following code example below, with two template classes, one base and one derived. I need to access a type in the base class from the derived class, but it says that it does not name a type. Why is this the case?
'Parameter' does not name a type
using namespace std;
template<typename PointT>
class BaseClass{
public:
BaseClass(){}
class Parameter{
Parameter(){}
};
};
template<typename PointT>
class DerivedClass : public BaseClass<PointT>{
public:
DerivedClass(){}
class ParameterExtended{
Parameter x;
};
};
You need this:
typename BaseClass<PointT>::Parameter x;
I am trying to forward declare a class that is derived from a template class that must also be forward declared.
Here is an example of the classes:
class TType {
public:
TType() { }
};
template<typename T>
class Base {
public:
Base() { }
};
class Derived : public Base<TType> {
public:
Derived() { }
};
Here is a failed guess at what I need:
class TType;
template<typename T> class Base;
class Derived : public Base<TType>; // This fails
Derived* pDerived;
Just forward declare the class name:
class Derived;
You can't include any more information about a class in its declaration; base classes, members, etc. can only be declared in the class definition.
This forward declaration can be used to do various things, including declaring pointers or references (such as pDerived in your example), and also declaring functions with Derived as an argument or return type. If you need to do anything that needs to know the class's size, base classes, or members, then you'll need the full definition.