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>(); }
};
Related
I'm having an issue where I've created a somewhat tangled hierarchy involving templates. The result is I'm having to put some code in the wrong header files just to get it to compile, and compilation is now fragile (I don't know if I can keep this project compiling if just the right function needs to be added.)
So I'm looking for a way to resolve this so that the code is nicely divided into proper files.
So without further ado, here is the code:
TemplatedBase.h
template <typename T> struct TemplatedBase
{
T value;
void go();
};
Derived.h
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
template <typename T> void TemplatedBase<T>::go()
{
// TemplatedBase<T> NEEDS USE OF Derived!!
// So TemplatedBase<T>::go() is appearing here in Derived.h,
// that's the only way I could get it to compile and it seems really
// out of place here.
Derived der;
der.hello();
}
main.cpp
#include <stdio.h>
#include "Derived.h"
int main(int argc, const char * argv[])
{
Derived d;
d.go();
return 0;
}
Isn't there a way I can put TemplatedBase<T>::go() into a file like TemplatedBase.cpp? Alas, it doesn't seem to work (you will see Undefined symbol: TemplatedBase<int>::go() in XCode at least).
You could do it by explicitly instantiating the template with a particular type in the cpp file:
// TemplatedBase.cpp
#include "TemplatedBase.h"
#include "Derived.h"
template <typename T>
void TemplatedBase<T>::go()
{
// TemplatedBase<T> NEEDS USE OF Derived!!
// So TemplatedBase<T>::go() is appearing here in Derived.h,
// that's the only way I could get it to compile and it seems really
// out of place here.
Derived der;
der.hello();
}
template struct TemplatedBase<int>; // This will make it work but now you can only use `TemplatedBase<int>`
// More instantiations go here...
But I wouldn't recommend doing this as this restricts what types you are able to use in TemplatedBase<T> (You'd have to manually add every single type yourself). So instead, use a templated type inside the go() member function (The trick here is that template parameters are not evaluated immediately):
// TemplatedBase.h
struct Derived; // Forward declaration
template <typename T>
struct TemplatedBase
{
T value;
void go()
{
go_impl();
}
private:
template <typename X = Derived>
void go_impl()
{
X der;
der.hello();
}
};
// Derived.h
#include "TemplatedBase.h"
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
Note: BTW, since C++20, one can just do:
// TemplatedBase.h
struct Derived; // Forward declaration
template <typename T>
struct TemplatedBase
{
T value;
void go()
{
[] <typename X = Derived>() {
X d;
d.hello();
}();
}
};
TemplatedBase and Derived are really coupled, so sharing the same header might be a viable option.
Else, you can create a file for your template definition (Header guards omitted):
// TemplatedBase.h
// Public header
#include "TemplatedBaseDecl.h"
#include "TemplatedBaseImpl.h"
// TemplatedBaseDecl.h
template <typename T>
struct TemplatedBase
{
T value;
void go();
};
// TemplatedBaseImpl.h
#include "TemplatedBaseDecl.h"
#include "Derived.h"
template <typename T> void TemplatedBase<T>::go()
{
Derived der;
der.hello();
}
// Derived.h
// Public header
#include "TemplatedBaseDecl.h" // Cannot use "TemplatedBase.h"
struct Derived : public TemplatedBase<int>
{
void hello()
{
printf("HI %d\n", value);
}
};
I recently got stuck in a situation like this:
class A
{
public:
typedef struct/class {…} B;
…
C::D *someField;
}
class C
{
public:
typedef struct/class {…} D;
…
A::B *someField;
}
Usually you can declare a class name:
class A;
But you can't forward declare a nested type, the following causes compilation error.
class C::D;
Any ideas?
You can't do it, it's a hole in the C++ language. You'll have to un-nest at least one of the nested classes.
class IDontControl
{
class Nested
{
Nested(int i);
};
};
I needed a forward reference like:
class IDontControl::Nested; // But this doesn't work.
My workaround was:
class IDontControl_Nested; // Forward reference to distinct name.
Later when I could use the full definition:
#include <idontcontrol.h>
// I defined the forward ref like this:
class IDontControl_Nested : public IDontControl::Nested
{
// Needed to make a forwarding constructor here
IDontControl_Nested(int i) : Nested(i) { }
};
This technique would probably be more trouble than it's worth if there were complicated constructors or other special member functions that weren't inherited smoothly. I could imagine certain template magic reacting badly.
But in my very simple case, it seems to work.
If you really want to avoid #including the nasty header file in your header file, you could do this:
hpp file:
class MyClass
{
public:
template<typename ThrowAway>
void doesStuff();
};
cpp file
#include "MyClass.hpp"
#include "Annoying-3rd-party.hpp"
template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>()
{
// ...
}
But then:
you will have to specify the embedded type at call time (especially if your function does not take any parameters of the embedded type)
your function can not be virtual (because it is a template)
So, yeah, tradeoffs...
I would not call this an answer, but nonetheless an interesting find:
If you repeat the declaration of your struct in a namespace called C, everything is fine (in gcc at least).
When the class definition of C is found, it seems to silently overwrite the namspace C.
namespace C {
typedef struct {} D;
}
class A
{
public:
typedef struct/class {...} B;
...
C::D *someField;
}
class C
{
public:
typedef struct/class {...} D;
...
A::B *someField;
}
If you have access to change the source code of classes C and D, then you can take out class D separately, and enter a synonym for it in class C:
class CD {
};
class C {
public:
using D = CD;
};
class CD;
This would be a workaround (at least for the problem described in the question -- not for the actual problem, i.e., when not having control over the definition of C):
class C_base {
public:
class D { }; // definition of C::D
// can also just be forward declared, if it needs members of A or A::B
};
class A {
public:
class B { };
C_base::D *someField; // need to call it C_base::D here
};
class C : public C_base { // inherits C_base::D
public:
// Danger: Do not redeclare class D here!!
// Depending on your compiler flags, you may not even get a warning
// class D { };
A::B *someField;
};
int main() {
A a;
C::D * test = a.someField; // here it can be called C::D
}
This can be done by forward declare the outer class as a namespace.
Sample: We have to use a nested class others::A::Nested in others_a.h, which is out of our control.
others_a.h
namespace others {
struct A {
struct Nested {
Nested(int i) :i(i) {}
int i{};
void print() const { std::cout << i << std::endl; }
};
};
}
my_class.h
#ifndef MY_CLASS_CPP
// A is actually a class
namespace others { namespace A { class Nested; } }
#endif
class MyClass {
public:
MyClass(int i);
~MyClass();
void print() const;
private:
std::unique_ptr<others::A::Nested> _aNested;
};
my_class.cpp
#include "others_a.h"
#define MY_CLASS_CPP // Must before include my_class.h
#include "my_class.h"
MyClass::MyClass(int i) :
_aNested(std::make_unique<others::A::Nested>(i)) {}
MyClass::~MyClass() {}
void MyClass::print() const {
_aNested->print();
}
I'm trying to generate header files of classes I'm reconstructing from what I disassembled with IDA. However I'm getting compile errors due to circular dependencies. For regular classes I solved it by declaring them in a separate file I include as a first. The thing is I cannot declare inner class without definition of an outer class which is the problem.
An example class structure:
Class A:
#include "B.h"
class A {
public:
class Nested {
public:
void foo(B::Nested &foo);
};
};
Class B:
#include "A.h"
class B {
public:
class Nested {
public:
void foo(A::Nested &foo);
};
};
You can forward declare the Nesteds in A and B, and define them afterward.
a.h
class A {
public:
class Nested;
};
B.h
class B {
public:
class Nested;
};
Nested.h
#include "A.h"
#include "B.h"
class A::Nested {
public:
void foo(B::Nested &foo);
};
class B::Nested {
public:
void foo(A::Nested &foo);
};
Use templates.
class A {
public:
class Nested {
public:
template<class B>
void foo(typename B::Nested &fo);
};
};
class B {
public:
class Nested {
public:
template<class A>
void foo(typename A::Nested &fo);
};
};
template<>
void A::Nested::foo<B>(B::Nested &fo){
}
template<>
void B::Nested::foo<A>(A::Nested &fo){
}
e.g. (Here the template has been moved up so the type doesn't have to be specified with each function call.)
#include <iostream>
class A {
public:
template <class B>
class Nested {
public:
std::string name() const { return "a"; }
void foo(typename B:: template Nested<A> &fo);
};
};
class B {
public:
template <class A>
class Nested {
public:
std::string name() const { return "b"; }
void foo(typename A:: template Nested<B> &fo);
};
};
template<>
void A::Nested<B>::foo(B::Nested<A> &fo){
std::cout << "A::Nested " << fo.name() << '\n';
}
template<>
void B::Nested<A>::foo(A::Nested<B> &fo){
std::cout << "B::Nested " << fo.name() << '\n';
}
int main()
{
A::Nested<B> a;
B::Nested<A> b;
a.foo(b);
b.foo(a);
}
When a compiler reads your file it is expecting declared entities.
You can forward declare the class but you would be missing the Nested Parameter type.
What you can do is to have a third class which breaks the circular dependency and inherits to the your nested classes:
class NestedBase {
};
Now use this base in your A nested class:
#include "NestedBase.h"
class A {
public:
class Nested : public NestedBase {
public:
void foo(NestedBase &foo);
};
};
And in your B nested class as well:
#include "NestedBase.h"
class B {
public:
class Nested : public NestedBase {
public:
void foo(NestedBase &foo);
};
};
Now with dynamic_cast in your method implementations you can convert them to your desired types and access whatever you declared in your Nested Classes.
#include "A.h"
#include "B.h"
B::Nested::foo(NestedBase &foo)
{
auto &fooA = dynamic_cast<A::Nested&>(foo);
...
}
I can't seem to figure out how to write the includes of the Visitor Pattern with this simple example. No matter what I do I always end up with circular dependencies, but no other way makes sense.
Also I apologize for the different header guards (pragma vs. #ifndef), I was testing #pragma out and hadn't updated the files yet.
Client.cpp
#include "OneVisitor.h"
#include "DataStructure.h"
int main (int argc, char * argv [])
{
OneVisitor v;
DataStructure d;
}
DataStructure.h
#ifndef _DATA_STRUCTURE_H_
#define _DATA_STRUCTURE_H_
#include "ElementA.h"
class DataStructure {
public:
DataStructure (Visitor & v)
{
std::cout << "ACCEPTS";
a->accept(v);
};
private:
ElementA * a;
};
#endif
Element.h
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
#include "Visitor.h"
#include <iostream>
class Element {
public:
virtual void accept (Visitor & v) = 0;
void talk ()
{
std::cout << "ELEMENT TALKING";
};
};
#endif
ElementA.h
#pragma once
#include "Element.h"
#include "Visitor.h"
class ElementA : public Element {
public:
virtual void accept (Visitor & v) override
{
v.Visit(*this);
};
void talk ()
{
std::cout << "ELEMENT A TALKING";
};
};
Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
#include "ElementA.h"
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif
OneVisitor.h
#ifndef _ONE_VISITOR_H_
#define _ONE_VISITOR_H_
#include "Visitor.h"
class OneVisitor : public Visitor {
public:
virtual void Visit (ElementA & a) override
{
a.talk();
};
};
#endif
When I run this, I get the error "Visitor has not been declared" in Element.h, ElementA.h, ElementB.h. How can i get Visitor defined in these classes without causing circular dependencies?
A visitor is a very abstract concept, and it makes sense to template it in this case. Using templates allows us to get rid of circular dependencies, and simplify things considerably.
// Visitor.hpp
#pragma once
template<class T>
class Visitor {
public:
virtual void visit(T& item) = 0;
virtual ~Visitor() = default;
};
Now, if you want to have visitor for Element, you could just use Visitor<Element>:
// Element.hpp
#pragma once
#include "Visitor.hpp"
#include <iostream>
class Element
{
public:
virtual void accept(Visitor<Element>& v)
{
v.visit(*this);
}
virtual void talk() {
std::cout << "Element talking!\n";
}
virtual ~Element() = default;
};
Now that we have these things, we can also write a function to convert lambdas into visitors:
template<class T, class Func>
struct FunctionVisitor : public Visitor<T> {
Func func;
FunctionVisitor() = default;
FunctionVisitor(FunctionVisitor const&) = default;
FunctionVisitor(FunctionVisitor&&) = default;
FunctionVisitor(Func const& func)
: func(func)
{
}
void visit(T& item) override {
func(item);
}
};
template<class T, class Func>
FunctionVisitor<T, Func> makeVisitor(Func const& f) {
return FunctionVisitor<T, Func>(f);
}
Bringing it all together
This allows us to write nice code like this:
#include "Element.hpp"
#include "Visitor.hpp"
#include <vector>
class ElemA : public Element {
public:
void talk() override {
std::cout << "ElemA talking!\n";
}
};
class ElemB : public Element {
public:
void talk() override {
std::cout << "ElemB talking!\n";
}
};
class ElemC : public Element {
public:
void talk() override {
std::cout << "ElemC talking!\n";
}
};
void visitAll(std::vector<Element*>& elements, Visitor<Element>& visitor) {
for(auto e : elements) {
e.accept(visitor);
}
}
int main() {
std::vector<Element*> elements {
new ElemA(),
new ElemB(),
new ElemC()
};
auto talk = [](Element& e) { e.talk(); };
visitAll(elements, makeVisitor<Element>(talk));
}
By using a forward declaration of the class ElementA; in Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
// Just use a forward declaration of the class ElementA;
// NOTE1: The include of ElementA.h is not needed anymore.
// NOTE2: The visitor.h doesn't need to know what is defined
// in ElementA, only your .cpp needs, this is how forward
// declaration works.
class ElementA;
class Visitor {
public:
virtual void Visit (ElementA & a) = 0;
};
#endif
I have several classes in a project I'm working on; the first is a Solver class, originally with a function template whose full definition is in the Solver header file, like so (just showing the bare necessities):
solver.h
class Solver {
public:
template<typename T>
void solve(T t);
}
template<typename T>
void Solver::solve(T t) {
// implementation here
}
Now, class A is used as template parameter for the solve function template as follows:
A.h
#include "solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething();
}
A.cpp
void A::doSomething() {
s.solve<A&>(*this);
}
So this is all fine and dandy as it is now, but for the purposes of the project, I need to move the definition of the solve() function template into an implementation file (solver.cpp) from the header file. As I understand it, I can do this as long as I add lines that explicitly state what types will be used with the function template, as follows:
solver.cpp
template<typename T>
void Solver::solve(T t) {
// implementation here
}
template void Solver::solve<A&>(A& a);
However this doesn't work when I try to compile solver, because in order to specify A as a type I want to use as a template parameter in solve.cpp, I need to have A not be an incomplete type. But A requires Solver in order to even compile - so I believe I have a circular dependency. Is there any way I can get around this issue?
I'm relatively new to all this, so take it easy on me please :) Much thanks.
Samoth is nearly right, you need class A; ("forward declaration"). But only before you use it, not before the Solver class:
Edited In response to comments, your minimal code sample was too minimal :) The real problem was Header Guards:
#ifndef SOLVER_H_INCLUDED_
#define SOLVER_H_INCLUDED_
class Solver {
public:
template<typename T>
void solve(T t);
};
#endif // SOLVER_H_INCLUDED_
And
// A.h
#ifndef A_H_INCLUDED_
#define A_H_INCLUDED_
#include "Solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething();
};
#endif // A_H_INCLUDED_
// Solver.cpp
#include "Solver.h"
#include "A.h"
template<typename T>
void Solver::solve(T t) {
// implementation here
}
// explicit instantiations
template void Solver::solve<int>(int);
// ...
template void Solver::solve<A&>(A&);
This will work
// main.cpp
#include "A.h"
int main()
{
A a;
a.doSomething();
}
The best way to pass-by circular dependencies is to do this :
class A; // before the class Solver
class Solver {
public:
template<typename T>
void solve(T t);
}
template<typename T>
void Solver::solve(T t) {
// implementation here
}
What you can do is:
solver.h
#ifndef SOLVER_H_INCLUDED_
#define SOLVER_H_INCLUDED_
class Solver {
public:
template<typename T>
void solve(T t);
};
#include "solver.cpp"
#endif
solver.cpp
#include "solver.h"
template<typename T>
void Solver::solve(T t) {
// implementation here
}
and a.hpp
#ifndef A_H_INCLUDED_
#define A_H_INCLUDED_
#include "solver.h"
class A {
private:
Solver s; //s is instantiated in constructor
public:
void doSomething()
{
s.solve(*this);
}
};
#endif