How can I declare a template friend function to a template class? - c++

Sorry, this question seems to have been asked many times, but I could not get the other answers to work for my setup. I have the following class and function setup:
namespace ddd {
template <typename T>
class A {
...
};
template <typename T, typename U>
A<T> a_func(const A<U> &a) {
...
}
}
I want to declare a_func as a friend of A, and I want it so that a_func is a friend for all instances of A, no matter which typename is used for T and U (e,g, a_func can access A).
Thanks!

You can do that this way (which looks like how you had it):
template<typename X>
class A {
template<typename T, typename U>
friend A<T> a_func(const A<U>& a);
};
template<typename T, typename U>
A<T> a_func(const A<U>& a) {
// whatever
}
Demo

Related

C++ template class, template member friend function matching rules

I have a templated class with a templated friend function declaration that is not having its signature matched when stated in a more direct, but seemingly equivalent, expression:
link to example on online compiler
#include <type_traits>
template <typename Sig> class Base;
template <typename R, typename ... Args> class Base<R(Args...)> { };
template <typename Sig, typename T> class Derived;
template <typename Sig> struct remove_membership;
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
// XXX: why are these two not equivalent, and only the 1st version successful?
template <typename T2>
friend auto foo(T2 const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T2>::operator())>::type> *;
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)> *;
};
template <typename F, typename R, typename ... Args>
struct remove_membership<R (F::*)(Args...) const> {
using type = R(Args...);
};
template <typename T>
auto foo(T const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type> *
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
int main(int, char **) { foo([](){}); } // XXX blows up if verbose friend decl. removed.
Inside member definitions of Derived<R(Args...), T> (for example, in the body of bar()), the types match, adding to my confusion:
static_assert(std::is_same<Base<R(Args...)>, Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type>>::value,
"signature mismatch");
Are there rules around template class template member function (and friend function) delarations and instantiations that make these preceding declarations distinct in some or all circumstances?
template <typename T2>
void foo(T2 const &)
template <typename T2>
auto foo(T2 const &)
-> std::enable_if_t<some_traits<T2>::value>;
Are 2 different overloads. Even if both return void (when valid).
2nd overload uses SFINAE.
(and yes, template functions can differ only by return type contrary to regular functions).
Your version is not identical but similar (&std::remove_reference_t<T>::operator() should be valid)
You can use the simpler template friend function:
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)>*;
};
template <typename T>
auto foo(T const &) -> Base<void()>* // friend with Derived<void(), U>
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
Demo
but you have then to implement different version of the template foo.
The problem can be reduced to:
template<class T>
struct identity {
using type=T;
};
class X {
int bar();
public:
template<class T>
friend T foo();
};
template<class T>
typename identity<T>::type foo() { return X{}.bar(); }
int main() {
foo<int>(); // error: bar is a private member of X
}
Even though we know identity<T>::type is always T, the compiler doesn't know that and would be wrong to assume so. There could be a specialization of identity<T> somewhere later in the code that resolves to some type other than T.
Therefore when the compiler sees the second declaration of foo it won't assume that it is the same friend foo declared before.

Partial specialization friend declaration

In the following code:
template <typename U, typename V> class A {};
template <typename U, typename V> class B {};
template <typename T>
class C {
template <typename U, typename V> friend class A; // Works fine.
// template <typename U> friend class B<U,T>; // Won't compile.
};
I want B<U,T> to be friend to C<T>, that is, the second parameter of B must match C's parameter, though its first parameter can be anything. How do I achieve this? The friend declaration of A<U,V> is too much, though I will take that if I can't restrict it any further.
Perhaps define a meta-function
template <typename, typename = void> struct FriendTraits { struct type{}; };
or something like that within C?
The first 2 lines of
template <typename, typename = void> struct FriendTraits { struct type{}; };
template <typename U> struct FriendTraits<U,T> { using type = B<U,T> ; } ;
template <typename U> friend typename FriendTraits<U,T>::type;
compiled, but not the important 3rd line (because it is the same problem).

Template factory function with additional args: friendship issue

I'm working on a piece of code that looks like this:
template<typename T>
class A {
// makeA should become a friend
A() {}
};
template<typename T, typename U>
A<T> makeA(const U & u) {
(void) u;
return A<T>();
}
int main() {
makeA<double>(3);
return 0;
}
But I cannot let makeA become a friend of A. Is this possible? What is the right syntax?
You could make it friend as:
template<typename T>
class A
{
template<typename TT, typename U>
friend A<TT> makeA(const U & u) ;
};
You could even define the friend function inside the class.
While the solution
template <typename T>
class A
{
template<typename TT, typename U>
friend A<TT> makeA(const U & u) ;
};
works, it suffers from the side effect that makeA<int, int> is a friend of not only A<int> but also a friend of A<double>, A<char>, etc. In other workds, makeA<TT, U> is a friend of every A<T>. The friendship granted by A<T> is too broad.
You can limit that by using a different design.
template <typename T> class AMaker;
template <typename T>
class A
{
A() {}
friend class AMaker<T>;
};
template<typename T> class AMaker
{
public:
template <typename U>
static A<T> make(const U & u)
{
(void) u;
return A<T>();
}
};
int main()
{
A<double> x = AMaker<double>::make(3);
return 0;
}
Here, friendship granted by A<T> is limited to only AMaker<T>. AMaker<int> is friend of A<int> but not of A<double>.
I have done some changes in your program
template
class A {
// makeA should become a friend
A() {}
public:
template<typename S,typename U>
friend A<S> makeA(const U & u); //this is correct way to makeA friend of A
};
template<typename T, typename U>
A<T> makeA(const U & u) {
(void) u;
return A<T>();
}
int main() {
makeA<double>(3);
return 0;
}
Now it will work as you can see here
http://ideone.com/1F1l3o
Here is a solution that does not use friend:
template<class T>
class A {
A() {}
public:
template<class U> static A make(U && u) {
return A();
}
};
template<class T, class U>
A<T> makeA(U && u) {
return A<T>::template make<U>(std::forward<U>(u));
}

Making certain specializations of a function template friend

Suppose I have
template<class T>
void f(T t);
and
template<class T>
class X
{
};
If I want only f<T> to be friend of X<T>, I declare:
template<class T>
class X
{
friend void f<>(T t);
};
Now suppose f is declared like this:
template<class T, class U>
void f(T t, U u);
I want to declare the following: for any type U f<T, U> is friend of X<T>. So I want f<int, char> to be friend of X<int>, but I don't want f<char, int> to be frient of X<int>. Is this possible? The following doesn't seem to compile
template<class T>
class X
{
template <class U>
friend void f<>(T t, U, u);
};
Please note that I'm aware how to declare the whole template as friend.
Apparently, there is no way in current C++ to do what I'm after.
[EDIT]
I had taken this idea from a website which stated this was possible,
but not properly tested it. As it turns out, this does not work,
so please disregard this suggestion.
As far as I can tell, what OP wants to do is not possible in c++...
[/EDIT]
The code as you posted it would partially specialize the function f, however this is not allowed.
To fix it, remove the empty angle brackets from the friend declaration:
template<class T>
class X
{
template <class U>
friend void f(T t, U, u);
};

Syntax of out-of-class definition of a template member function of a template class

template<typename A, typename B>
class mindF_ck
{
template<typename C>
inline bool ouch(C & c_in);
};
How do I define the signature for ouch out-of-class ? I send a query to my brain but it keeps coming up blank ;)
template<typename A, typename B>
template<typename C>
bool mindf_uck<A,B>::ouch(C & c_in) {
}
template <typename A, typename B>
template <typename C>
bool mindf_ck<A, B>::ouch(C& c_in) {
// ... code ...
}