Template class with a friend function which is inside a nested namespace - c++

I'm trying to create a template class with a friend function which is inside a nested namespace. It works fine if I remove all the namespaces or if I remove all the templatization. But with both in place it won't compile. Let's look at some code:
namespace MyNamespace
{
// Forward declaration
template <typename Type>
class Container;
// Forward declaration
namespace AccessPrivateImplementation
{
template <typename Type>
Type getValue(Container<Type>* container);
}
// Templatized class
template <typename Type>
class Container
{
friend Type AccessPrivateImplementation::getValue(Container<Type>* volume);
private:
Type value;
};
// Friend function inside a namespace
namespace AccessPrivateImplementation
{
template <typename Type>
Type getValue(Container<Type>* container)
{
return container->value;
}
}
}
int main(int argc, char* argv[])
{
MyNamespace::Container<int> cont;
MyNamespace::AccessPrivateImplementation::getValue(&cont);
return 0;
}
The compiler (VS2010) tells me:
error C2248: 'MyNamespace::Container::value' : cannot access private member declared in class 'MyNamespace::Container'
Does anyone have any idea what I'm missing?

The friend declaration inside the Container class template declares a friend non-template function getValue() that lives in the AccessPrivateImplementation namespace.
However, you haven't provided such a function. Instead, what you have in the AccessPrivateImplementation namespace is a function template, whose appropriate specialization you want to be friend of Container<T> (for a given T).
To achieve this, the declaration you need is:
friend Type AccessPrivateImplementation::getValue<>(Container<Type>* volume);
// ^^
Here is a live example that shows your code compiling with the above fix.

As per my comment, if you declare the friend like so it will work:
friend Type AccessPrivateImplementation::getValue<>(Container<Type>* volume);
^^

Related

Is it possible to invoke an injected friend template function?

To be consistent with other (non-template) functions in a class I wanted to define and invoke a friend template function.
I can define it with no problem (see function t below).
namespace ns{
struct S{
void m() const{}
friend void f(S const&){}
template<class T>
friend void t(S const&){}
};
template<class T>
void t2(S const& s){}
}
However later I am not able to invoke this t function in any way?
int main(){
ns::S s;
s.m();
f(s);
// t<int>(s); // error: ‘t’ was not declared in this scope (I was expecting this to work)
// ns::t<int>(s); // error: ‘t’ is not a member of ‘ns’
// ns::S::t<int>(s); // error: ‘t’ is not a member of ‘ns::S’
}
Even if it is not possible at all, I am surprised that I am allowed to define it.
I tested this with gcc 8 and clang 7.
What you need for this to work are a couple of forward declarations.
The below two lines of code should come before the namespace ns.
struct S; //Needed because S is used as a parameter in the function template
template<class T> void t(S const&);
And then this form of call will work inside main.
t<int>(s);
See demo here.

template specialization for member functions in a templated class [duplicate]

I have a templated class with an templated member function
template<class T>
class A {
public:
template<class CT>
CT function();
};
Now I want to specialize the templated member function in 2 ways. First for having the same type as the class:
template<class T>
template<> // Line gcc gives an error for, see below
T A<T>::function<T>() {
return (T)0.0;
}
Second for type bool:
template<class T>
template<>
bool A<T>::function<bool>() {
return false;
}
Here is how I am trying to test it:
int main() {
A<double> a;
bool b = a.function<bool>();
double d = a.function<double>();
}
Now gcc gives me for the line marked above:
error: invalid explicit specialization before ‘>’ token
error: enclosing class templates are not explicitly specialize
So gcc is telling me, that I have to specialize A, if I want to specialize function, right?
I do not want to do that, I want the type of the outer class to be open ...
Is the final answer: it is not possible? Or is there a way?
Yes, this is the problem:
error: enclosing class templates are not explicitly specialized
You cannot specialize a member without also specializing the class.
What you can do is put the code from function in a separate class and specialize that, much like basic_string depends on a separate char_traits class. Then then non-specialized function can call a helper in the traits class.
You can use overload, if you change the implementation.
template <typename T>
class Foo
{
public:
template <typename CT>
CT function() { return helper((CT*)0); }
private:
template <typename CT>
CT helper(CT*);
T helper(T*) { return (T)0.0; }
bool helper(bool*) { return false; }
};
Simple and easy :)

Friend of function in dependent scope

Is this code invalid:
template <class T> struct A;
class C {
template <class T> friend void A<T>::foo();
};
In GCC 6.1.0 it says:
error: member 'void A<T>::foo()' declared as friend before type 'A<T>' defined
template <class T> friend void A<T>::foo();
Clang 3.8.0:
warning: dependent nested name specifier 'A<T>::' for friend class declaration
is not supported; turning off access control for 'C' [-Wunsupported-friend]
And Visual Studio 2015 crashes:
fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'f:\dd\vctools\compiler\cxxfe\sl\p1\c\template.cpp', line 8952)
template <class T> friend void A<T>::foo();
More specifically, is A required to be defined before the friend declaration?
template <class T> struct A;
class C {
static void foo();
template <class T> friend void A<T>::f();
};
template <class T> struct A {
void f() { }
};
If so, why?
You refer to A's member function foo. This function is not known to exist yet, because you only forward declare A.
In other words, you'll have to declare A<T>::foo before C, as the GCC message tries to tell you (the other two are rather cryptic). This means you have to declare the complete interface of A before C, instead of only forward declaring it.
Solution
You can declare f as a friend of C in the following way:
class C;
template <class T> struct A {
void f(C const &c);
};
class C {
int i = 42;
public:
static void foo();
template <class T> friend void A<T>::f(C const &c);
};
template <class T> void A<T>::f(C const &c) { std::cout << c.i << std::endl; }
Live Demo
Justification
According to the standard §3.3.2/p6 Point of declaration [basic.scope.pdecl]:
After the point of declaration of a class member, the member name can
be looked up in the scope of its class. [ Note: this is true even if
the class is an incomplete class. For example,
struct X {
enum E { z = 16 };
int b[X::z]; // OK
};
— end note ]
The diagnostic is rather misleading both for GCC and CLANG. The real problem with your code is not the fact that you're trying to access the definition of an incomplete type, but rather is that you can only refer to a class member name only after it has been declared.
The first problem is (I think) from §9.3/7 [class.mfct] and probably some other places in the standard (see clang message below and 101010's answer):
Previously declared member functions may be mentioned in friend declarations.
This problem is similar to the one from this question.
Since you did not declare A<T>::f before C, you cannot declare it has a friend of C.
But there is an hidden problem behing clang's message, if you make A a non-templated class, the message is different:
Incomplete type A in nested name specifier.
Which is closer to gcc message than the actual one, this is because clang's warning is about something else. Per §14.5.4/5 [temp.friend], the standard allows member of class template to be friend, so this must be valid:
template <typename T>
struct A {
void f ();
};
class C {
template <typename T>
friend void A<T>::f(); // Ok, A<T>::f is already declared
void private_member (); // See below
};
But clang still complains:
warning: dependent nested name specifier 'A::' for friend class declaration
is not supported; turning off access control for 'C' [-Wunsupported-friend]
clang does not support such friend declaration, so it simply turns off access control for C, meaning that:
C c;
c.private_member();
Will be "valid" everywhere, which may not be what you want.
Firstly, Forward declaration of a class is not sufficient if you need to use the actual class type, for example, if you need to use it as a base class, or if you need to use the methods of the class in a method.
Since here you try to use its details "foo()", there is no way compiler knows what is A::foo().. Compiler cannot distinguish if it is a typo (or) actual function.. it needs to know the declaration of A::foo() before you can use it.
If you still want to only to forward declare the class and make it a friend, see if friend classes fit your situation
template <class T> struct A;
class C{
template <class T> friend struct A;
};

Is this full template specialization, and is it allowed? [duplicate]

I have a templated class with an templated member function
template<class T>
class A {
public:
template<class CT>
CT function();
};
Now I want to specialize the templated member function in 2 ways. First for having the same type as the class:
template<class T>
template<> // Line gcc gives an error for, see below
T A<T>::function<T>() {
return (T)0.0;
}
Second for type bool:
template<class T>
template<>
bool A<T>::function<bool>() {
return false;
}
Here is how I am trying to test it:
int main() {
A<double> a;
bool b = a.function<bool>();
double d = a.function<double>();
}
Now gcc gives me for the line marked above:
error: invalid explicit specialization before ‘>’ token
error: enclosing class templates are not explicitly specialize
So gcc is telling me, that I have to specialize A, if I want to specialize function, right?
I do not want to do that, I want the type of the outer class to be open ...
Is the final answer: it is not possible? Or is there a way?
Yes, this is the problem:
error: enclosing class templates are not explicitly specialized
You cannot specialize a member without also specializing the class.
What you can do is put the code from function in a separate class and specialize that, much like basic_string depends on a separate char_traits class. Then then non-specialized function can call a helper in the traits class.
You can use overload, if you change the implementation.
template <typename T>
class Foo
{
public:
template <typename CT>
CT function() { return helper((CT*)0); }
private:
template <typename CT>
CT helper(CT*);
T helper(T*) { return (T)0.0; }
bool helper(bool*) { return false; }
};
Simple and easy :)

Specialization of templated member function in templated class

I have a templated class with an templated member function
template<class T>
class A {
public:
template<class CT>
CT function();
};
Now I want to specialize the templated member function in 2 ways. First for having the same type as the class:
template<class T>
template<> // Line gcc gives an error for, see below
T A<T>::function<T>() {
return (T)0.0;
}
Second for type bool:
template<class T>
template<>
bool A<T>::function<bool>() {
return false;
}
Here is how I am trying to test it:
int main() {
A<double> a;
bool b = a.function<bool>();
double d = a.function<double>();
}
Now gcc gives me for the line marked above:
error: invalid explicit specialization before ‘>’ token
error: enclosing class templates are not explicitly specialize
So gcc is telling me, that I have to specialize A, if I want to specialize function, right?
I do not want to do that, I want the type of the outer class to be open ...
Is the final answer: it is not possible? Or is there a way?
Yes, this is the problem:
error: enclosing class templates are not explicitly specialized
You cannot specialize a member without also specializing the class.
What you can do is put the code from function in a separate class and specialize that, much like basic_string depends on a separate char_traits class. Then then non-specialized function can call a helper in the traits class.
You can use overload, if you change the implementation.
template <typename T>
class Foo
{
public:
template <typename CT>
CT function() { return helper((CT*)0); }
private:
template <typename CT>
CT helper(CT*);
T helper(T*) { return (T)0.0; }
bool helper(bool*) { return false; }
};
Simple and easy :)