Forward Declare instance of Template Class with Virtual Functions - c++

I have created a template class A<T> in mynamespace which I need to forward declare to use in class B in mynamespace2. Is it possible to forward declare a specific instance of A for use in B, namely A<int>?
File: a.h
#include "b.h"
namespace mynamespace{
template <class T>
class A{
A(T); // constructor
mynamespace2::B* b_attribute;
};
}
File: b.h
/* How to forward declare A<int>? This doesn't work:
*
* namespace mynamespace{
* class A<int>;
* }
*
* neither does this:
*
* namespace mynamespace{
* template <class T>
* class A<T>
* }
*/
namespace mynamespace2{
class B{
B();
mynamespace::A<int>* a_attribute; // for use over here
virtual void f(A<int>*); // note: virtual function
};
}
I appreciate any help.

This is no different than forward-declaring anything else, except that you have to get the namespace right:
namespace mynamespace{
template <class T> class A;
}
A is declared in mynamespace, so you have to specify it, as such.
If you really want to avoid explicitly specifying the namespace every time, add a using declaration:
namespace mynamespace2{
using mynamespace::A;
class B{
B();
A<int>* a_attribute; // for use over here
};
}
Once a using declaration is made, you can just refer to A anywhere within mynamespace2.
Note that you must still forward-declare the template in the other namespace, before pulling it in with using.

Related

Explicit template instantiation of templated friend of templated class in C++

I have a main class MainClass whose private member variables should be visible to a friend class FriendClass.
Both are templated by an int called dim, and they both have their respective header and source files (and are thus in different translation units).
Since MainClass doesn't really depend on FriendClass (and to avoid circular dependency) I forward declare FriendClass as a template class when doing the friend declaration in MainClass.
Additionally, at the end of the source files I explicitly instantiate both classes for dim = 2 and dim = 3.
However, when I compile I get an error that the private member variable of MainClass is private within this context when I try to use it in a method of FriendClass.
I suspect this has something to do with the fact that a particular instantiation of FriendClass does not recognize that the corresponding instantiation of MainClass has declared it a friend, but I'm not sure how to fix the problem.
Code:
// MainClass.hpp
#ifndef MAIN_CLASS_HPP
#define MAIN_CLASS_HPP
template <int dim>
class MainClass
{
public:
MainClass(){};
private:
template <int friend_dim>
class FriendClass;
friend class FriendClass<dim>;
double private_member = 3.0;
};
#endif
// MainClass.cpp
#include "MainClass.hpp"
template class MainClass<2>;
template class MainClass<3>;
// FriendClass.hpp
#ifndef FRIEND_CLASS_CPP
#define FRIEND_CLASS_CPP
#include "MainClass.hpp"
template <int dim>
class FriendClass
{
public:
FriendClass(){};
void print_main_class(MainClass<dim> &main_class);
};
#endif
// FriendClass.cpp
#include "FriendClass.hpp"
#include <iostream>
template <int dim>
void FriendClass<dim>::print_main_class(MainClass<dim> &main_class)
{
std::cout << main_class.private_member << std::endl;
}
template class FriendClass<2>;
template class FriendClass<3>;
// main.cpp
#include "MainClass.hpp"
#include "FriendClass.hpp"
int main()
{
const int dim = 2;
MainClass<dim> main_class;
FriendClass<dim> friend_class;
friend_class.print_main_class(main_class);
return 0;
}
Code available to compile live at onlinegdb.com
You have declared two different class templates both named FriendClass. Probably unintentionally.
One is the global FriendClass and the other is MainClass::FriendClass.
You can fix this by forward declaring your class template in the namespace it exists in.
// MainClass.hpp
#ifndef MAIN_CLASS_HPP
#define MAIN_CLASS_HPP
template <int>
class FriendClass;
template <int dim>
class MainClass
{
public:
MainClass(){};
private:
friend FriendClass<dim>;
// Now the global FriendClass is a friend.
double private_member = 3.0;
};
#endif

How do you forward declare header files?

I'm trying to forward declare the header files #include<memory_resource> and #include<deque>. But the following doesn't seem to work. This is pseudo-code:
A.hpp
class memory_resource;
class deque;
class A
{
public:
...
private:
std::pmr::deque<index_t> tempQueue;
}
A.cpp
#include<memory_resource>
#include<deque>
...
No, you cannot "forward declare header files".
In order to define a member of a given type, that type must first be defined. You can achieve that by including the header that defines it.
Since you define the class A in A.hpp and that class has a member of type std::pmr::deque<index_t>, you must include the definition of std::pmr::deque into A.hpp, before the definition of the class A.
Here is a working example:
// A.hpp
#include <deque>
#include <memory_resource>
using index_t = int;
class A
{
std::pmr::deque<index_t> tempQueue;
};
For a rule of thumb, you should not forward declare anything from the standard library, unless the class specifically says it can be forward declared.
To use anything from the standard library, you must actually include them:
// A.hpp
#include <memory_resource>
#include <deque>
class A {
std::pmr::deque<index_t> tempQueue;
}
Now, let's pretend you are not forward declaring anything from the standard library. You don't forward declare header files, instead you forward declare classes.
So if you have a class named deque defined in my_deque.cpp file, in another file, you might do:
// my_deque.cpp
class deque { /* some definitions ... */ };
// A.hpp
class deque;
You don't forward declare the file, my_deque, instead you forward declare the class deque .
Secondly, the deque class was actually located in a namespace. So in order to forward declare deque in another file, you must declare it within the same namespace:
// my_deque.cpp
namespace my_std::pmr{
class deque { /* some definitions ... */ };
}
// A.hpp
namespace my_std::pmr{
class deque;
}
Third, deque was actually a templated class, so to forward declare it, you must also declare it along all the template argument, including anything with default arguments:
// my_deque.cpp
namespace my_std::pmr{
template<typename T, typename Allocator = std::allocator<T>>
class deque { /* some definitions ... */ };
}
// A.hpp
namespace my_std::pmr{
template<typename T, typename Allocator = std::allocator<T>>
class deque;
}
Fourth, you cannot use a forward declared class as a class member directly. In order to create a class, you must be able to calculate the size of the class. To do that, you must also know the sizes of each class members. However, you can't know the size of a forward declared class, because you don't know what members does that class have, so you can't use a forward declared class as a class member.
However, you can use a pointer of a forward declared class as a class member, since all pointers have the same size:
// my_deque.cpp
namespace my_std::pmr{
template<typename T, typename Allocator = std::allocator<T>>
class deque { /* some definitions ... */ };
}
// A.hpp
namespace my_std::pmr{
template<typename T, typename Allocator = std::allocator<T>>
class deque;
}
class A{
my_std::pmr::deque<index_t>* p_tempQueue;
}

Friending/Using a class in a different namespace

If the class G is in the namespace GSpace and it needs to be friends with the class M in the global namespace what do you have to do? I thought this would work:
/////////////////////M.h//////////////////////
#include "GFile.h"
class M
{
public:
friend class GSpace::G; // doesn't work, throws error
}
After researching on StackOverflow a bit, I found this answer https://stackoverflow.com/a/3843743/1797424
/////////////////////M.h//////////////////////
namespace GSpace
{
class G;
}
class M
{
public:
friend class GSpace::G; // works, no error
private:
GSpace::G gClassMember; // errors: "M uses undefined class GSpace::G"
};
// Note that G.h includes M.h so I do not include it here,
// instead I have it included in M.cpp
That does work for getting the class friended. However, it creates an issue when I actually declare a class member using that type, because the class is not defined. GFile.h
Am I misunderstanding how #include and forward declaration behaves, or is it some kind of implementation issue on the side of the compiler (not likely, I'm assuming)?
Because your member is not a pointer or reference, the compiler needs to know the size of G. You can't use a forward declaration.
As noted in the comment, you need to qualify G with the namespace.
Here is code which compiles for me:
namespace GSpace
{
class G
{
};
}
class M
{
public:
friend class GSpace::G;
private:
GSpace::G gClassMember;
};
int main() {return 0;}
Try the following
namespace GSpace
{
class G;
}
class M
{
public:
friend class GSpace::G;
}
namespace GSpace
{
class G { /* definition of the class */ };
}

Passing anonymous classes to private member functions

Is it possible to use a class defined in an anonymous namespace as a parameter in a private member function? I haven’t found a way to forward declare AnonymousHelperClass in the header.
// C.h
class C
{
// ...
private:
void Boing(AnonymousHelperClass &helper);
};
.
// C.cpp
namespace
{
class AnonymousHelperClass
{
// . . .
};
}
C::Boing(AnonymousHelperClass &helper)
{
// ...
}
No, because there is no way to name the type in the header file.
However, you could turn the private member function into a template:
// C.h
class C
{
public:
void Foo();
private:
template <typename TAnonymousHelper>
void Boing(TAnonymousHelper&);
};
Then define it in the source file and use it with the AnonymousHelperClass:
// C.cpp
#include "C.h"
namespace
{
class AnonymousHelperClass { };
}
template <typename TAnonymousHelper>
void C::Boing(TAnonymousHelper& x) { }
void C::Foo()
{
AnonymousHelperClass x;
Boing(x);
}
Though really, it's probably easier just to rework your logic such that the private member function can be a namespace-scope function in the .cpp file.
No, because unnamed namespaces (that's what they're actually called) are defined like this in the C++ standard:
7.3.1.1 Unnamed namespaces [namespace.unnamed]
1. An unnamed-namespace-definition behaves as if it were replaced by
namespace unique { /* empty body */ }
using namespace unique;
namespace unique { namespace-body }
where all occurrences of unique in a translation unit are replaced by
the same identifier and this identifier differs from all other
identifiers in the entire program.
So with your class it's equivalent to:
namespace SomeUniqueNameGeneratedByTheCompiler {}
using namespace SomeUniqueNameGeneratedByTheCompiler;
namespace SomeUniqueNameGeneratedByTheCompiler
{
class AnonymousHelperClass
{
// . . .
};
}
So the full qualification of the AnonymousHelperClass class is ::SomeUniqueNameGeneratedByTheCompiler::AnonymousHelperClass, not ::AnonymousHelperClass. So even if you did this:
class AnonymousHelperClass; // Forward declaration
class C
{
// ...
private:
void Boing(AnonymousHelperClass &helper);
};
That forward declaration refers to a different AnonymousHelperClass. You could put the forward declaration in the SomeUniqueNameGeneratedByTheCompiler namespace, but since only the compiler knows this name, it can't be done.

Forward declarations: templates and inheritance

When writing a framework I got following problem:
I have class A and class B wchich is derived from class A.
class A has a function wchich returns B*.
Of course, it's not difficult:
#include <iostream>
using namespace std;
class B; // forward declaration
class A
{
public:
B* ReturnSomeData();
};
class B : public A
{
};
// Implementation:
B* A::ReturnSomeData()
{
return new B; // doesn't matter how the function makes pointer
}
int main()
{
A sth;
cout << sth.ReturnSomeData(); // print adress
}
However I had to use templates like here:
#include <iostream>
using namespace std;
// This "forward declaration":
template <class Number>
class B<Number>;
// cannot be compiled:
// "7 error: 'B' is not a template"
template <class Number>
class A
{
public:
B<Number>* ReturnSomeData();
};
template <class Number>
class B : public A<Number>
{
};
// Implementation:
template <class Number>
B<Number>* A<Number>::ReturnSomeData()
{
return new B<Number>;
}
int main()
{
A<int> sth;
cout << sth.ReturnSomeData();
}
Look at the code. As you can see I don't know how to deal with unknown by A B*. Is it possible to write forward declaration? Or I need something different?
Yes, I searched and I see there are many posts about template declarations but can't find solve for my individual problem. It's a bit complex for me.
Thanks for help.
Your forward declaration is incorrect. It needs to be:
template <class Number>
class B;
^ no argument list