This is a follow-up on my answer to this question.
The original answer I posted does not have any namespaces, and it solves the problem. However, the OP subsequently made an edit claiming that the solution does not work if the class is inside a namespace.
My initial reaction was that you can make it work by simply having using N::f;
either at global scope or inside main()
(or any other function). While that is certainly the case, the OP (justifiably) commented that this is not ideal, and I agree.
Nevertheless, I still thought that calling N::f
without having using N::f;
should work just fine, but to my surprise I got an undefined reference error when I tried the following:
#include<iostream>
namespace N
{
template<class T>
class Class;
template<typename U, typename W>
Class<W> f (Class<U>& C, const Class<U>& D);
template<class T>
class Class
{
protected: // this could be private
T m_t;
public:
Class()
:
m_t(T())
{}
Class(T t)
:
m_t(t)
{}
T& getT()
{
return m_t;
}
template<typename U, typename W>
friend Class<W> f (Class<T>& C, const Class<T>& D)
{
C.m_t += D.m_t;
Class<W> R;
std::cout << R.m_t << std::endl; // I don't want this to be possible
return R;
}
};
}
int main()
{
N::Class<int> C(42), D(24);
std::cout << N::f<int, char>(C, D).getT() << std::endl;
}
error: undefined reference to N::Class<char> N::f<int, char>(N::Class<int>&, N::Class<int> const&)'
.
At this point, I went on to try different compiler versions and discovered that the above works as it does without a namespace
with GCC < 6 but not with GCC > 6. ICC 17 also seems to pick up on the protected member access inside f
, but not ICC 18. Clang never picks it up.
Which is the intended behaviour? Should the definition be made available to the linker in this case without using N::f;
?.
Edit 1:
To clarify, I want to retain the intended behaviour, namely restricting f
to be a friend
only to Class
instantiations that match its arguments (so in the example f
would be friend
to Class<T>
but not to Class<W>
).
f
in the definition depend on the template parameterT
. The reason for having<typename U, typename W>
beforef
is to match the forward declaration. In the accepted answer in the original question, the pattern is essentially the same: a struct templatetemplate<typename T> struct fs
which contains a functionf
with arguments depending onT
. Essentially, I am usingClass
itself as the helper struct, and that is whyf
needs to be defined inside the class. I am unaware of anything in the standard that forbids that, but maybe I'm missing something. – Fright