How to make a specialized function template a friend to some class? - c++

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?

Related

Template wrangling

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);
}
};

How to organize classes containing mixture of templates and friends?

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().

Circular dependency with template function

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>(); }
};

Declare static functions as friend function?

I have a class MyClass declaration in a header file interface.h and some static functions (foo and bar and a few more) in file1.cpp. The static functions are only used inside file1.cpp but they need to modify private/protected members of MyClass`.
// in "interface.h"
class MyClass {
// maybe declare as friend?
// friend static void foo(MyClass &ref);
private:
double someval;
}
// in "file1.cpp"
static void foo(MyClass &ref) {
ref.someval = 41.0;
}
static void bar(MyClass &ref) {
ref.someval = 0.42;
}
// function that uses foo/bar
void doSomething(MyClass &ref) {
foo(ref);
}
Idea 1: Somehow declare them as friends of MyClass?
Why its not good: They are static AND are in a different compilation unit. Besides that would expose them to the user of MyClass who does not need to know anything about them.
Idea 2: Don't have idea 2.
Sort of linked: Is it possible to declare a friend function as static?
Sort of linked: Is it possible to declare a friend function as static?
Personally I find the whole friend thing a bit of a hack that breaks encapsulation but you've asked a valid question and the answer is that you can achieve what you want with a helper class:
file1.h
class MyClass {
private:
double someval;
friend class MyClassHelper;
};
file1.cpp
#include "file1.h"
struct MyClassHelper {
static void mutateMyClass(MyClass& ref) {
ref.someval=42;
}
};
// in "file1.cpp"
static void foo(MyClass &ref) {
MyClassHelper::mutateMyClass(ref);
}
Are you really sure you want to do it like this? Are you sure you don't want to encapsulate MyClass's mutators inside MyClass itself?
As weird as it may sound (and look), you can actually read & write private members of a class / struct.
It's not pretty, and certainly not encouraged, but doable.
template<typename T>
struct invisible
{
static typename T::type value;
};
template<typename T>
typename T::type invisible<T>::value;
template<typename T, typename T::type P>
class construct_invisible
{
construct_invisible(){ invisible<T>::value = P; }
static const construct_invisible instance;
};
template<typename T, typename T::type P>
const construct_invisible<T, P> construct_invisible<T, P>::instance;
struct MyClass_someval{ typedef double MyClass::*type; };
template class construct_invisible<MyClass_someval, &MyClass::someval>;
static void foo(MyClass &ref) {
ref.*invisible<MyClass_someval>::value = 41.0;
}
When I first saw it I also thought: HOLY S***!
// in "interface.h"
class MyClass {
// maybe declare as friend?
// friend static void foo(MyClass &ref);
public:
friend class SetSomevalClass; // make the classes friends
private:
double someval;
};
class SetSomevalClass // functor class(or function class)
{
public:
double operator()(MyClass n, double data) // this could have been void
{
n.someval = data; //set somevalue to data
return n.someval; //return somevalue
// return is solely used to show result in foo() and bar()
}
};
// in "file1.cpp"
static void foo(MyClass &ref)
{
SetSomevalClass s; //create functor object
//s(ref, 40);
//this would be the end of the foo function(uncommented) if we did not want to show the result
std::cout << "foo()" << s(ref, 40) << std::endl;
//simply to show result
}
static void bar(MyClass &ref)
{
SetSomevalClass s;
//s(ref,2);
//this would be the end of the foo function(uncommented) if we did not want to show the result
std::cout << "bar()" << s(ref, 2) << std::endl;
}
// function that uses foo/bar
void doSomething(MyClass &ref) //calls both foo() and bar()
{
foo(ref);
bar(ref);
}
int main()
{
MyClass s;
doSomething(s);
}// end main

Template function with a forward declared class

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)
}