In one of my projects I have a tree data structure, that might contain values of a generic type T
.
In order to reduce compilation times and dependencies I tried to move implementation details from the tree node class Node
to class NodeImpl
. The internals of Node
are private and should be only accessed at defined entry points, for example by the getName
function.
Only people that are interested in using getName
should include NodeImpl
in their source files. This is how I think to reduce my compilation times and dependencies.
But for some reason the following three toys classes will not compile. It says no access to private members. What I'm doing wrong?
File main.cpp
:
#include <iostream>
#include "Node.h"
#include "NodeImpl.h"
int main(int argc, char** args) {
Node<int> n("Test", 2);
std::cout << getName(n) << std::endl;
}
File Node.h
:
#pragma once
#include <string>
template<typename T>
class NodeImpl;
template<typename T>
class Node {
public:
typedef T value_type;
Node(const std::string& name, const T& value) : name(name), value(value) {}
private:
std::string name;
T value;
friend class NodeImpl<T>;
};
File NodeImpl.h
:
#pragma once
#include "Node.h"
template<typename T>
std::string getName(Node<T>& n);
template<typename T>
class NodeImpl {
NodeImpl(Node<T>& node) : mNode(node) {
}
Node<T>& mNode;
std::string name() {
return mNode.name;
}
friend std::string getName(Node<T>& n);
};
template<typename T>
std::string getName(Node<T>& n) {
auto x = NodeImpl<T>(n);
return x.name();
}
The warning produced by GCC gives insight:
In other words, your class
NodeImpl<int>
was befriending a global functionstd::string getName(Node<int> &)
, which is unrelated to the functionstd::string getName<int>(Node<int> &)
instantiated from the function templatetemplate <class T> std::string getName(Node<T> &)
forT = int
.So the correct solution is this:
This [live example] shows that this solution indeed works.