Explicit template instantiation of templated friend of templated class in C++ - 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

Related

Forward Declare instance of Template Class with Virtual Functions

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.

Cannot access protected class member on the second level of inheritance of class templates in C++

I'm experiencing a problem accessing a protected class member from a class template derived from another class template. I have three class templates, the second derived from the first, and and third one derived from the second. Specifically,
class1.h:
template <typename T> class class1
{
protected:
T data;
int a;
public:
class1();
void someMethod();
};
class2.h:
#include "class1.h"
template <typename T> class class2: public class1<T>
{
using class1<T>::a;
T otherData;
public:
class2();
};
class3.h:
#include "class2.h"
template <typename T> class class3: public class2<T>
{
using class2<T>::a;
public:
class3();
};
class2.cpp:
#include "class2.h"
#include <iostream>
template <typename T> class2<T> :: class2()
{
std::cout<<"Creating class2 object!"<<std::endl;
a = 2;
}
template class class2<double>;
Finally, class3.cpp:
#include "class3.h"
#include <iostream>
template <typename T> class3<T> :: class3()
{
std::cout<<"Creating class3 object!"<<std::endl;
a = 3;
}
template class class3<double>;
When I compile class2.cpp into an object file, like this:
g++ -c -O3 -std=c++11 -Wall -o class2.o class2.cpp
everything goes well. However, a get an error when compiling class3.cpp in the same way. A following error pops up:
In file included from class2.h:4:0,
from class3.h:4,
from class3.cpp:1:
class3.h: In instantiation of ‘class class3<double>’:
class3.cpp:11:16: required from here
class1.h:9:6: error: ‘int class1<double>::a’ is protected
int a;
^
Replacing using class2<T>::a; with using class1<T>::a; in class3 doesn't help.
What's causing this error exactly and how can I avoid it if I really need to access variable a from within class3? Why is it that the first level of inheritance (class2) doesn't detect any problems, and the second one (class3) does? Thanks for any comments.
NOTE: I tried the same type of inheritance, but without templates and removed both lines containing using, and compilation goes well (access to variable a is now granted in class3). The problem definitely has to do with templates.
Your class2 definition is the same as the following:
template <typename T> class class2: public class1<T>
{
private: // default section
using class1<T>::a;
T otherData;
public:
class2();
};
It is because private is the default section for the members of classes. So the a member becomes private here and can't be inherited by the class3. You should explicitly place using class1<T>::a; statement in protected or public section of the class2 definition:
template <typename T> class class2: public class1<T>
{
T otherData;
protected: // <-- added
using class1<T>::a;
public:
class2();
};
Now it can be accessed from the class2 derived classes (including class3).

Calling a template method from another template method in C++?

I am currently having an issue with templated methods. I have this public class implementing a template method:
namespace Private { class InternalClass; }
namespace Public
{
class PublicClass
{
public:
PublicClass();
virtual ~PublicClass();
template<class T>
bool Add(bool primary);
private:
Private::InternalClass* _pInternal;
};
template<class T>
bool PublicClass::Add(bool primary) { return _pInternal->Add<T>(primary); }
}
The internal class is implemented that way:
namespace Private
{
class InternalClass
{
public:
InternalClass();
virtual ~InternalClass();
template <class T>
bool Add(bool primary);
};
template<class T>
bool InternalClass::Add(bool primary) { return false; }
}
As this internal class header won't be available with the provided sources, I must class forward it within the PublicClass header and I add the include to PrivateClass.h inside the PublicClass.cpp file.
1) Any idea why I would be getting the following error:
error : member access into incomplete type 'Private::InternalClass' / note: forward >declaration of 'Private::InternalClass'
2) What would be the best way of hiding my PublicClass::Add() implementation?
UPDATED
Reason for error at 1) is because of this as stated by Cornstalks.
For 2), how can I hide my implementation without including PrivateClass.h within the PublicClass header file?
You have encountered a very interesting problem - you want to implement the PImpl idiom where the privately implemented class has a template method. Well, this can be solved, meaning you CAN hide the template's implementation, but only when you know which types will be used to instantiate your Add<T> method in your program.
Say, your template will work only with types AClass and BClass. Then you can split your files as follows (comments are inlined):
File public.h:
#ifndef PUBLIC_H
#define PUBLIC_H
// Forward declaration ! It's sufficient in this case !
namespace Private { class InternalClass; }
// Declare all classes your Add<T> method should work with
struct AClass {};
struct BClass {};
namespace Public
{
class PublicClass
{
public:
PublicClass() {}
virtual ~PublicClass() {}
template <typename T>
bool Add(bool primary); // DO NOT implement this method, just declare
private:
Private::InternalClass* _pInternal;
};
// "Explicit instantiation declarations", for each type the method will work with:
extern template bool PublicClass::Add<AClass>(bool primary);
extern template bool PublicClass::Add<BClass>(bool primary);
}
#endif
File public.cpp:
#include "public.h"
// NOTE: this is hidden in CPP file, noone will see your implementation
namespace Private
{
class InternalClass
{
public:
InternalClass() {}
virtual ~InternalClass() {}
template <typename T>
bool Add(bool primary);
};
// Magic! Here is the actual implementation of your private method
template <typename T>
bool InternalClass::Add(bool primary)
{
return false;
}
}
namespace Public
{
// Original definition moved to CPP file !
template <typename T>
bool PublicClass::Add(bool primary)
{
return _pInternal->Add<T>(primary);
}
// And again list the allowed types, this time using "explicit instantiation definitions"
template bool PublicClass::Add<AClass>(bool primary);
template bool PublicClass::Add<BClass>(bool primary);
}
File main.cpp:
#include "public.h"
int main()
{
Public::PublicClass pc;
pc.Add<AClass>(true); // works !
pc.Add<BClass>(false); // works !
// pc.Add<int>(true); linker error as expected,
// becuase there is no explicit instantiation for Add<int>
return 0;
}

C++: Combining private global variables and templates

Suppose there is a global variable in a translation unit. It is constant, but not compile time constant (it is initialized with an object that has a non constexpr constructor). It is declared static since it should be private to the translation unit. Obviously, that global is defined in the .cpp file. However, now I have added a method template to that file that needs the global variable. Since it is a method that will be used by other translation units, it has to be put into the header. However, once it is in the header it can no longer access the global variable. What is the best practice to solve this problem?
There is, but a little tricky way to achieve your goals:
The variable is private, available only to some elements.
Your function template can access it.
Use private static variable in a class defined in header, and make your function/class templates friend of this class.
YourFile.h
class PrivateYourFileEntities {
private:
static const int SomeVariable;
// ... other variables and functions
template <class T>
friend class A;
template <class T>
friend void func();
// the rest of friends follows
};
template <class T>
void A<T>::func() {
int a = PrivateYourFileEntities::SomeVariable;
}
template <class T>
void func() {
int a = PrivateYourFileEntities::SomeVariable;
}
YourFile.cpp
const int PrivateYourFileEntities::SomeVariable = 7;
Put the method declaration into .h file and method body into .cpp file like:
.h file:
#include <iostream>
void myfunc1();
void myfunc2();
.cpp file:
#include "myheader.h"
static int myglobalvar=90;
void myfunc1()
{
cout << myglobalvar << endl;
}
void myfunc2()
{
cout << "Oh yeah" << endl;
}

C++ class declarations and namespaces

I'm having an issue with a C++ library I'm trying to write. It's the usual setup, one cpp file, one header file. I want the header file to only expose the parts that are meant to be used (I have an abstract base class for instance, I don't want in the header file). So far, I'm just working with a single file (I assume this should make no difference, as includes are done by the preprocessor, which doesn't care about anything).
You'll note that the "header file" is spread over two spots, before and after the header implementation file.
#include <stdio.h>
// lib.h
namespace foo {
template <class T> class A;
}
// lib.cpp
namespace foo {
template <class T> class A {
private:
T i;
public:
A(T i) {
this->i = i;
}
T returnT() {
return i;
}
};
};
// lib.h
namespace foo {
template <class T> T A<T>::returnT();
}
// foo.cpp
void main() {
foo::A<int> a = foo::A<int>(42);
printf("a = %d",a.returnT());
}
So, naturally, I'd like my header file to contain just
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
But my compiler does not like this (it complains that returnT is not a member of foo::A<T>. The reason I don't want to put the class declaration itself in the header is that then it would (as I understand it), contain all the private and similar stuff, which I'd like to hide.
Maybe it's just me, but the following header file seems "bad", at least as an "interface specification." It exposes some of the internals of A, which a user of the lib would not need to know about.
// lib.h
namespace foo {
template <class T> class A {
private:
int i;
public:
A(T);
T returnT();
};
}
// lib.cpp
namespace foo {
template <class T> A<T>::A(T i) {
this->i = i;
}
template <class T> T A<T>::returnT() {
return i;
}
};
Is this the accepted way of doing it? I'd like a more abstract header file, if at all possible.
You cannot separate the definition of a template from its declaration. They both have to go into the header file together.
For "why?" I recommend reading "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?".
I may have misread your question. To address what may also be your question, this is not valid:
namespace foo {
template <class T> class A;
template <class T> T A<T>::returnT();
}
It is not valid for the same reason that this is not valid:
namespace foo {
class A;
int A::returnT();
}
Member functions must be declared inside the definition of the class.
There are two problems with .cpp files you are dealing here:
I.
If you want to put an instance of that class on the stack (like you do in your main()) the compiler needs to know the size of the class (to allocate enough memory). For that it needs to know the members and by that the complete declaration.
The only way to hide the class' layout away is to built up an interface and a factory method/function and put the instance on the heap in the factory.
As an example (without the template; see below to know why):
namespace foo {
class IA {
public:
virtual ~IA();
virtual int returnT() = 0;
static IA *Create();
};
}
In your .cpp you then do:
namespace foo {
class A : public IA {
private:
int i;
public:
A() :
i(0) {
}
virtual ~A() {
}
virtual int returnT() {
return i;
}
};
IA::~IA() {
}
IA *IA::Create() {
return new A();
}
}
BTW: Using smart pointers would be suggested...
II.
Since you are using a template the method definitions must be either visible via header file or explicitly instantiated for a specific set of types.
So you can split up your code into a lib.h and a lib_impl.h:
lib.h:
namespace foo {
template <typename T> class IA {
public:
virtual ~IA() {
}
virtual T returnT() = 0;
static IA *Create();
};
}
lib_impl.h:
namespace foo {
template <typename T> class A : public IA<T> {
private:
T i;
public:
A() :
i(T()) {
}
virtual ~A() {
}
virtual T returnT() {
return i;
}
};
template <typename T> IA<T> *IA<T>::Create() {
return new A<T>();
}
}
so you include the lib_impl.h where ever you need the impleemntations.
To use the explicit instantiations add a lib.cpp and just let that file allow to include lib_impl.h:
lib.cpp:
#include <lib_impl.h>
namespace foo {
template class IA<int>;
template class A<int>;
template class IA<float>;
template class A<float>;
template class IA<char>;
template class A<char>;
// ...
}