Noob question here. I have a class with a circular dependency so I forward declared it. Now, I'm planning to try out a template with this.
//in C.h
class C {
public:
virtual void getMap();
}
// in A.h
class C;
class A {
public:
virtual void foo(C *c);
template <class T>
void changeProperty(C *c, string& s) {
void* obj = c->getMap()->at(s); // does not compile
// (did not include the rest for brevity)
}
}
This fails to compile at the line specified stating that Class C doesn't have a function 'getMap()'. Can this be fixed? If so, how?
Move the definition of changeProperty out of the class (so it's not inline) and place it somewhere after the definition of class C has been seen.
So the preprocessed result will end up as something like:
class C;
class A {
public:
virtual void foo(C *c);
template <class T>
void changeProperty(C *c, string& s);
}
// ...
class C {
public:
virtual void getMap();
}
// ...
template <class T>
void A::changeProperty(C *c, string& s)
{
void* obj = c->getMap()->at(s); // compiles
// (did not include the rest for brevity)
}
Related
I'm trying to find a way to make a function that is a friend to a given class. That function is another class' method and is a specialization of a template. Without specialization, I have the following compiling code in Visual Studio:
ClassA.h:
#pragma once
#include "classB.h"
class A
{
private:
int data;
void Operate();
public:
A();
~A();
template<class T> friend void B::DoSomething(const T& arg);
};
ClassB.h:
#pragma once
class B
{
private:
int data;
template<typename T> void DoSomething(const T& arg)
{
T copy = arg;
copy.Operate();
data = 3;
};
/*
template<> void DoSomething(const A& arg)
{
A copy = arg;
copy.Operate();
data = 4;
};
*/
public:
B();
~B();
};
ClassA.cpp:
#include "classA.h"
A::A()
{
data = 1;
}
A::~A()
{
}
void A::Operate()
{
data = 2;
}
ClassB.cpp:
#include "classB.h"
B::B()
{
data = 1;
}
B::~B()
{
}
How do I specialize the template and make it a friend instead of the entire template? If that is possible, where do I place it then? Do I need forward declarations anywhere? Which headers would I need to include, etc.?
I tried to uncomment the block in classB.h and add #include "classA.h" on top of it. I also tried to replace the line template<class T> friend void B::DoSomething(const T& arg); in classA.h with something like template<> friend void B::DoSomething(const A& arg);. Nothing helped. It refuses to compile.
I would appreciate any insight!
To make B::DoSomething<int> a friend of A, use
friend void B::template DoSomething<int>(const int& arg);
To make B::DoSomething<A> a friend of A, use
friend void B::template DoSomething<A>(const A& arg);
Please note that in order to be able to do that, DoSomething has to be a public member of B.
Further reading: Where and why do I have to put the "template" and "typename" keywords?
I have two C++ classes such that:
The first class contains a pointer to the second class and has template function that calls second class's public method through a pointer. The function is defined already in the class declaration, for the reason of being a template.
The second class allows the first class to access its private members through friendship mechanism.
Given that, my question is: how do I organize the sources/headers/forward declarations for this situation?
Whatever I tried, it just doesn't compile to an object file.
One sequence is this:
class Class2;
class Class1
{
Class2 * c2;
public:
template<typename T> T DoSomething(T& X)
{
c2->Func();
return X;
};
void FuncFromClass1();
};
class Class2
{
int data;
public:
Class2() : data(0) {};
void Func();
friend void Class1::FuncFromClass1();
};
void Class2::Func()
{
int i;
}
void Class1::FuncFromClass1()
{
int j;
c2 = new Class2;
c2->data = 1;
}
Barks invalid use of incomplete type ‘class Class2’ because it doesn't recognize c2->Func();.
The other one is:
class Class1;
class Class2
{
int data;
public:
Class2() : data(0) {};
void Func();
friend void Class1::FuncFromClass1();
};
class Class1
{
Class2 * c2;
public:
template<typename T> T DoSomething(T& X)
{
c2->Func();
return X;
};
void FuncFromClass1();
};
void Class2::Func()
{
int i;
}
void Class1::FuncFromClass1()
{
int j;
c2 = new Class2;
c2->data = 1;
}
Doesn't recognize friend void Class1::FuncFromClass1();.
The compilation is tried as g++ -c -std=c++11 -Wall test.cpp.
Note I'd rather not make Class1 as entire friend, rather want to keep only one of its methods as a friend to Class2, if at all possible.
Also, I haven't tried the exact same example in Visual Studio in Windows, but saw an entirely isomorphic situation like the one described (within a bigger project) and no complaints came from VS as far as I recall. Is it unique to g++?
Move the implementation of the member function template where definition of Class2 is known.
class Class2;
class Class1
{
private:
Class2 * c2;
public:
// Delcare, don't define
template<typename T> T DoSomething(T& X);
void FuncFromClass1();
};
class Class2
{
private:
int data;
public:
Class2() : data(0) {};
void Func();
friend void Class1::FuncFromClass1();
};
// Define
template<typename T>
T Class1::DoSomething(T& X)
{
c2->Func();
return X;
};
Note that the proposed solution is simple if both classes are defined in one .h file. If the classes are defined in separate .h files, things get a little bit more complex. You'll have to make sure that the .h file where Class1::DoSomething() is defined is #included in every .cpp file where you want to use Class1::DoSomething().
I have a class A with the following declaration (A.h file):
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#endif
and a class B deriving from that class (B.h file):
#ifndef __B_DEFINED__
#define __B_DEFINED__
#include <iostream>
#include "A.h"
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
So far, so good. My issue is that the function A::doThat() uses B::doThis():
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
Usually, the circular dependency would not be an issue because I would just define A::doThat() in the .cpp file. In my case however, doThat is a template function so I can't do that.
Here are the solutions I have envisioned so far:
Defining the template function A::doThat() in a .cpp file. The issue with that is that I need to instantiate explicitly all the calls with various template arguments (there might be many in the real case).
After the declaration of the A class in A.h, add #include "B.h" and then define the A::doThat() function. This works fine in visual studio but g++ does not like it.
Is there a neat way to solve this problem?
EDIT: In the real case, there is not just one child class B, but several (B, C, D, etc.) The function A::doThat() depends on all of them. The function B::doThis() is also templated.
A default template parameter for the B class could work:
#include <iostream>
// include A.h
class B;
class A
{
public:
template<typename T, typename U = B> inline void doThat() const
{
U b; b.doThis();
}
};
// include B.h
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
// main
int main()
{
A a;
a.doThat<int>();
}
Usually the best way to allow a parent to call a child function is to declare the function as a pure virtual function in the parent and override it in the children.
#include <iostream>
class A
{
public:
virtual ~A() = default;
template<typename T> inline void doThat() const
{
// do some other stuff
doThis();
}
virtual void doThis() const = 0; // pure virtual function
};
class B: public A
{
public:
void doThis() const override
{
std::cout << "do this!" << std::endl;
}
};
int main()
{
B b;
A* ap = &b;
ap->doThat<int>();
}
The following does work with g++:
File A.h:
#ifndef __A_DEFINED__
#define __A_DEFINED__
class A
{
public:
template<typename T> inline void doThat() const;
};
#include "B.h"
template<typename T> inline void A::doThat() const { B b; b.doThis(); }
#endif
File B.h:
#include <iostream>
#include "A.h"
// We check for the include guard and set it AFTER the inclusion of A.h
// to make sure that B.h is completely included from A.h again.
// Otherwise the definition of A::doThat() would cause a compiler error
// when a program includes B.h without having included A.h before.
#ifndef __B_DEFINED__
#define __B_DEFINED__
class B : public A
{
public:
void doThis() const { std::cout << "do this!" << std::endl; }
};
#endif
File test_A.cpp:
// In this test case we directly include and use only A.
#include "A.h"
#include "A.h" // We test whether multiple inclusion causes trouble.
int main() {
A a;
a.doThat<int>();
}
File test_B.cpp:
// In this test case we directly include and use only B.
#include "B.h"
#include "B.h" // We test whether multiple inclusion causes trouble.
int main() {
B b;
b.doThat<int>();
b.doThis();
}
Alternative Idea:
I do not know whether you (or some coding conventions) insist on separate header files for each class, but if not the following should work:
You can put the definitions of class A and class B and of the member function template A::doThat<typename>() (in this order) together in one header file AandB.h (or whatever name you like).
This cries for polymorphism. There are two options using polymorphism:
Dynamic polymorphism, i.e. make A an abstract base class and call doThis() virtually:
struct A
{
virtual void do_this() const = 0;
template<typename T>
void doThat() const { doThis(); }
};
struct B : A
{
void doThis() const override { /* ... */ }
};
Of course, this only works if doThis() is not templated. If you need that, you could use
Static polymorphism, i.e. CRTP, when
template<typename Derived>
struct A
{
template<typename T>
void doThat() const { static_cast<const Derived*>(this)->template doThis<T>(); }
};
struct B : A<B>
{
template<typename T>
void doThis() const { /* ... */ }
};
If (as in your example code) B::doThis() is not called for the same object, but for some temporary, you could
template<typename typeB>
struct A
{
template<typename T>
void doThat() const { typeB b; b.template doThis<T>(); }
};
I'm having some problems implementing a class based on a abstract parent class. It's saying PolishStack is an abstract class, even though all virtual functions are coded:
In file included from braincalc.cpp:10:
./polstack.h:15:7: error: explicit specialization of non-template class 'PolishStack'
class PolishStack<T> : public AbstractStack<T> {
^ ~~~
braincalc.cpp:13:21: error: variable type 'PolishStack<char>' is an abstract class
PolishStack <char> stk;
^
./abstractstack.h:53:16: note: unimplemented pure virtual method 'isEmpty' in
'PolishStack'
virtual bool isEmpty() const = 0;
Here's my class header:
#ifndef POLSTACK_H
#define POLSTACK_H
#include <iostream>
using namespace std;
#include "abstractstack.h"
template <typename T>
class PolishStack<T> : public AbstractStack<T> {
T* data;
int mMax;
int mTop;
public:
PolishStack();
bool isEmpty();
const T& top() const throw (Oops);
void push(const T& x);
void pop();
void clear();
//my funcs:
void printStack();
~PolishStack();
};
#endif
I don't want to give all my code away due to other students cheating, so I'll post the function that the error is complaining about:
#include "polstack.h"
//...
template <typename T>
bool PolishStack<T>::isEmpty() {
if(mTop == 0)
return true;
return false;
}
//...
As others have stated it should be:
template<typename T>
class PolishStack : public AbstractStack<T>
./abstractstack.h:53:16: note: unimplemented pure virtual method 'isEmpty' in
'PolishStack'
virtual bool isEmpty() const = 0;
You're missing the const:
template<typename T>
bool PolishStack<T>::isEmpty() const
// ^^^^^
{
if(mTop == 0)
return true;
return false;
}
Note: You should use the override keyword to be informed when you try to override a function using a different signature (i.e., you're introducing a new function overload instead of overriding the virtual one).
template<typename T>
class PolishStack : public AbstractStack<T>
{
public:
...
bool isEmpty() const override;
...
};
It's hard to tell without all the code, but one thing I noticed is that this:
class PolishStack<T> : public AbstractStack<T> {
should be just:
class PolishStack : public AbstractStack<T> {
That'll fix the first error for sure and potentially (but maybe not) the second.
Try changing to
template <typename T>
class PolishStack : public AbstractStack<T>
As a side note: Exception specifiers throw (Oops) are deprecated.
Ok, maybe not the best title, but here's the deal:
I have a templated interface:
template<typename T>
class MyInterface
{
public:
struct MyStruct
{
T value;
};
virtual void doThis(MyStruct* aPtr) = 0;
};
and an implementation:
template <typename T>
class MyImpl : public MyInterface<T>
{
public:
void doThis(MyStruct* aPtr)
{
} // doThis
};
However, the compiler complains:
In file included from MyTest.cpp:3:0:
MyImpl.h:7:17: error: ‘MyStruct’ has not been declared
void doThis(MyStruct* aPtr)
Why is that?
The following compiled for me:
template<typename T>
class MyInterface
{
public:
struct MyStruct
{
T value;
};
virtual void doThis(MyStruct* aPtr) = 0;
};
template <typename T>
class MyImpl : public MyInterface<T>
{
public:
void doThis(typename MyInterface<T>::MyStruct* aPtr)
{
}
};
int main() {
MyImpl<int> t;
}
The main change is that you need to qualify that the MyStruct was defined within MyInterface<T>.
Since the compiler cannot determine what kind of identifier is the templated subtype, you must help it using the typename keyword. (See When is the "typename" keyword necessary? for more details on typename)