Making certain specializations of a function template friend - c++

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

Related

Template friend function of template class that introduces a new template parameter

Thanks to Daniel Frey's answer to this post, I know how to declare a template friend function to a template class with the same template parameters. Unfortunately, the syntax for declaring a friend function with additional template parameters still escapes me. I would like to achieve something like this:
template <typename T>
class Obj;
template <typename T>
Obj<T> make_obj(T t);
template <typename T, typename RetVal>
RetVal ret_obj(T t);
template <typename T>
class Obj {
private:
T & t;
Obj (T & t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
template <typename RetVal>
friend RetVal ret_obj<T, RetVal>(T t);
};
template <typename T>
Obj<T> make_obj(T t) {
return Obj<T>(t);
}
template <typename T, typename RetVal>
RetVal ret_obj(T t) {
return RetVal(make_obj(t).t);
}
I know that the same question has already been asked in this post, but the accepted answer there does not seem to be what I want: changing the parameter name to T2 makes the function a friend of all specializations of the object, while I want to keep T the same as in the class.
It is impossible to let friend declarations refer to partial specializations - either they refer to a specific specialization or to the primary template. Moreover, function templates cannot be partially specialized anyway.
What is not possible with function templates is often doable using class templates though:
template <typename T>
struct ret_obj_helper {
// Here goes the original definition of ret_obj - the important difference
// is the location of the template parameter T, which is the one
// fixed by the friend declaration below
template <typename RetVal>
RetVal ret_obj(T t) {return RetVal(make_obj(t).t);}
};
// I guess RetVal, having to be explicitly specified, better goes first (?)
template <typename RetVal, typename T>
RetVal ret_obj(T&& t)
{
// Overcomplicated for the sake of perfect forwarding
return ret_obj_helper<typename std::remove_reference<T>::type>{}.
template ret_obj<RetVal>(std::forward<T>(t));
}
template <typename T>
class Obj {
private:
T t;
Obj (T t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
// Make all specializations of the member function template
// of ret_obj_helper<T> a friend, regardless of the return type
template <typename RetVal>
friend RetVal ret_obj_helper<T>::ret_obj(T t);
};
Demo.

How to specialize a templated member-function into a templated class in C++?

With regards to this question: How to create specialization for a single method in a templated class in C++? ...
I have this class:
template <typename T>
class MyCLass {
public:
template <typename U>
U myfunct(const U& x);
};
// Generic implementation
template <typename T>
template <typename U>
U MyCLass<T>::myfunct(const U& x) {...}
And I want to specialize myfunct for doubles.
This is what I do:
// Declaring specialization
template <>
template <typename T>
double MyCLass<T>::myfunct(const double& x);
// Doing it
template <>
template <typename T>
double MyCLass<T>::myfunct(const double& x) {...}
But it does not work.
That's not possible in C++. You can only specialise a member function template if you also specialise all enclosing class templates.
But anyway, it's generally better to overload function templates instead of specialising them (for details see this article by Herb Sutter). So simply do this:
template <typename T>
class MyCLass {
public:
template <typename U>
U myfunct(const U& x);
double myfunct(double x);
};

enable_if seems to work outside a class but not inside

Here is my somewhat odd code:
template <typename T&>
class A {
public:
void b(typename std::enable_if<!std::is_pointer<T>::value, T>;::type o) {}
void b(typename std::enable_if<std::is_pointer<T>::value, T>;::type o) {}
};
template <typename T>
void b(typename std::enable_if<!std::is_pointer<T>::value, T>::type o) {}
template <typename T>
void b(typename std::enable_if<std::is_pointer<T>::value, T>::type o) {}
If I ifdef out the method b and call b<int *>(pi) where pi is int *, everything compiles.
If I ifdef out the function b (outside class) and call A<int *> a; a.b(pi), I get the following error:
error: no type named 'type' in 'std::__1::enable_if<false, int *>'
Why the inconsistency and how can I fix the problem so that I can use the methods in A?
The problem is, that SFINAE only works during overload resolution and only if the function itself is a template. In your method case, the whole class is a template, meaning that there is no substitution of the template parameter (remember: SFINAE == "Substitution Failure Is Not An Error").
At the point of instantiation, the method signatures look like this (nevermind the call to them):
void A<int*>::b(std::enable_if<false, int*>::type o) // error
void A<int*>::b(std::enable_if<true, int*>::type o)
To fix this, make the methods templates too:
template<class T>
class A{
public:
template<class U>
void b(U o, typename std::enable_if<!std::is_pointer<U>::value>::type* = 0){}
// same for the other version
};
On a side note, letting the template argument get deduced is the better way to use SFINAE, so you should modify the free functions to look like this:
template<class T>
void b(T o, typename std::enable_if<!std::is_pointer<T>::value>::type* = 0){}
// same for the other version
In C++11, you can even use the template parameters for SFINAE:
template<class T, EnableIf<std::is_pointer<T>> = {}>
void b(T o);
Utilizing an alias from the blog entry linked from here:
namespace detail{ enum class enabler{}; }
template<class Cond, class T = detail::enabler>
using EnableIf = typename std::enable_if<C::value, T>::type;
For the explanation, see Xeo's answer.
For the work-around: just add a dummy template parameter to the method
#include <utility>
#include <type_traits>
template <typename T>
class A {
public:
template <typename U = T>
void b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o);
template <typename U = T>
void b(typename std::enable_if<std::is_pointer<U>::value, U>::type o);
};
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<!std::is_pointer<U>::value, U>::type o) {}
template <typename T>
template <typename U>
void A<T>::b(typename std::enable_if<std::is_pointer<U>::value, U>::type o) {}
int main() {
A<int> a;
a.b(0);
}
Live Demo Here.
You are not using SFINAE correctly because the compiler can't deduce the argument for enable_if<...>::type and probably that's why it fails.
Correct declarations of free-standing functions would be:
template <typename T>
typename std::enable_if<!std::is_pointer<T>::value, void>::type b(T o);
template <typename T>
typename std::enable_if<std::is_pointer<T>::value, void>::type b(T o);
In this particular case plain function overloading can be used as well:
template <typename T>
void b(T);
template <typename T>
void b(T*);

How can I declare a template friend function to a template class?

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

friend template function of template class

I have the following simplified code:
template <class T>
class A
{
public:
template <class U>
static U foo(T* p)
{
p;
return U();
}
};
class B
{
/*template <class T>
template <class U>
friend U A<T>::foo<U>(T*);*/
friend B A<B>::foo<B>(B*);
B()
{}
public:
};
...
A<B>::foo<B>(nullptr);
And it works quite well. But the things that I've not managed to do are commented:
/*template <class T>
template <class U>
friend U A<T>::foo<U>(T*);*/
I don't know what the syntax I should use to make it works. So I need to generalize my friend declaration to all possible types. I've tried quite a few variants of syntax but had no success. Could some one point me out what should I write instead of my commented code to make it works?
Thanks!
What you're looking for is
template <class T>
template <class U>
friend U A<T>::foo(T*);
The following works on IdeOne.com
#include <iostream>
template <class T>
class A
{
public:
template <class U>
static U foo(T* p)
{
p;
return U();
}
};
class B
{
template <class T>
template <class U>
friend U A<T>::foo(T*);
B() {}
public:
void hello() const
{
std::cout << "I'm a B!" << std::endl;
}
};
int main(int, char*[])
{
A<B>::foo<B>(NULL).hello();
}
I will agree with the othe commenters, friends and templates simply don't mix, at least not in any consistent way with across a range of compilers. The standard probably states exactly what should work, though that will likely not help you. Sad but true.
Friend is often not a good idea anyhow, it might be better to consider how to write the code without friendship, or use the "poor man's friend" of a public method with a comment indicating it is not for general use.