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
Related
I have a class template that implements a number of functions. I want to be able to also add specialized version of this class which has only a few functions that override those of the base, when a specific type is declared. I know I could achieve this with a class template and explicit specializations of it. However I also want to:
Have the explicit specializations uniquely named, similar to how a base and derived class are uniquely named.
Call the Base functions from an instantiated Derived object, either inside a Derived function, or explicitly as below with obj1.Foo
This is the (simplified) example code I am trying to make work:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
template<>
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
In myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
template<>
Derived::Bar(int& input) { // Do something int-dependent }
In main.cpp
int main()
{
Base<int> obj1 = new Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
However this code fails with the explicit specialization of non-template Derived error, among others. I've read a lot of StackOverflow threads to get me this far, but I haven't found any that have helped me make this compile. So my questions are:
Is combining class templates with class inheritance possible in this way?
Why does the compiler label the Derived class a non-template despite me explicitly using that keyword?
What is the correct syntax that will make this code work? (assuming what I am trying to do is possible)
EDIT: Following the suggesting of HTNW, I can turn Derived into a regular class by removing the template<> prefix. This will allow everything to compile up to obj1.Foo(input). It seems that the instantiated Derived class can't find or access the base Foo function.
Thanks to ravnsgaard and HTNW for the helpful suggestions which got me to a solution. The key was to remove the template<> keyword from the Derived class (because I wanted it to be a class and not a class template) and declaration of Base<int> at the end of the source file. So the working code looks like this:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
in myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
Derived::Bar(int& input) { // Do something int-dependent }
template class Base<int>; // VERY IMPORTANT.
In main.cpp
int main()
{
Base<int> &&obj1 = Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
In particular, without the template class Base<int>; declaration at the end of myClasses.cpp, the call to obj1.Foo will fail with an error complaining that Derived has no such function.
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
I have a base class which has a virtual function :
class Base {
...
virtual void myFunction() { assert(0 && "not implemented yet"); }
}
and a derived (template) class of Base :
DerviedClass.hpp :
Template<typename T>
class DerivedClass : public Base, public T {
...
void myFunction();
}
DerivedClass.cpp :
template <>
void DerivedClass<ClassA>::myFunction() {
//Something ClassA is suppose to do
}
This compiles. But when I try to instanciate a DerivedClass<ClassB> I get the error :
IProject.o:-1: erreur : undefined reference to `DerivedClass<ClassB>::myFunction()'
Why do I have this error? Why it does not take Base::myFunction instead of forcing me to implement a generic myFunction in DerivedClass or a specialized function DerivedClass::myFunction?
Note : the assert in myFunction is because ClassB is not supposed to call myFunction during runtime. For exemple if myFunction is getRadius, DerivedClass<Circle>::getRadius() is okay but DerivedClass<Square>::getRadius() should not be called.
Note 2 : The other topics I found were not clear about this point
Why it does not take Base::myFunction instead of forcing me to implement a generic myFunction in DerivedClass or a specialized function DerivedClass::myFunction?
You forced that yourself, by the declaration:
void myFunction();
Consider fully specializing the class template, which will generate classes conditionally with or without overriding myFunction, e.g.:
template <typename T>
class DerivedClass : public Base, public T {
// not overriding
};
template <>
class DerivedClass<ClassA> : public Base, public ClassA {
void myFunction() override;
};
template <>
void DerivedClass<ClassA>::myFunction() {
// something ClassA is supposed to do
}
If there's some common stuff, you can put it in:
template <typename T>
class DerivedClassCommons : public Base, public T {
// common stuff
};
and then refactor DerivedClass to use single inheritance of this class template.
That's it for your question, but as others were noting, I think you have a bigger, design problem.
Another method to fix the compiler error (not the design error) is to move the definition of myFunction to the derived template:
class Base {
virtual void myFunction() = 0;
}
template<typename T>
class DerivedClass : public Base, public T {
void myFunction() {
throw "not implemented, go away";
}
}
and then specialise only the methods you need:
template <>
void DerivedClass<ClassA>::myFunction() {
//Something ClassA is suppose to do
}
The function is already declared for all types. Definition might come from anywhere, including other compilation units. You'll only need the definition when the function is referred - and your virtual function is (implicitly) referred during construction.
Here a brief example of a code that works. It helps to introduce the actual question.
The specifiers for the visibility are the same used in the real code.
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived>
class Class: public Base {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
It follows the previous example, even though slightly modified.
A template parameter has been added to the base class and the derived one has been updated accordingly.
This one doesn't compile.
template<typename T>
class Base {
public:
using foo = int;
virtual ~Base() { }
protected:
static foo bar() noexcept {
static foo v = 0;
return v++;
}
};
template<class Derived, typename T>
class Class: public Base<T> {
static foo get() noexcept {
static foo v = bar();
return v;
}
};
int main() { }
The error is quite clear indeed and the problem is not to solve it:
main.cpp:18:12: error: ‘foo’ does not name a type
static foo get() noexcept {
^
main.cpp:18:12: note: (perhaps ‘typename BaseComponent<T>::foo’ was intended)
The actual question is: why foo is not visible without a scope specifier in the second example?
I mean, Class is derived from Base<T>, that is (at least in my mind) a fully defined type, thus foo should be part of the base class and thus visible to the derived one, as it happens in the first example.
It follows an example that, according to what I guess of the problem, actually compiles and should not, or at least should behave like the previous one:
template <typename T>
struct B {
using foo = T;
};
struct D: public B<int> {
static foo bar;
};
int main() {
B<int> *b = new D;
}
Could it be due to the fact that the derived class is not a templated one in this case?
Honestly, it seems to me a bit strange, because the foo type is part of the base class that is still a templated one, so it shouldn't be much different from the previous one.
It goes without saying that I'm wrong, but I cannot figure out what's wrong in my thoughts.
Thank you in advance for the help.
That's because of name lookup rules. If your base class is a template, the unqualified name in base is not resolved. The reason is that later in your code you may have a template specialization of that base which doesn't define the name, or for which the name means something completely different. It's too complicated for the compiler to figure out whether you have a specialization, and if so, whether your name means the same thing in it. So it prefers to defer the name lookup. To make the compiler "believe you", then you need to either use a qualified name, or this->name instead (for members, not for typedefs), and the compiler will resolve the name.
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.