How to match template friend function in a template class - c++

I have a template class that declares a friend function which itself has template parameters. The code looks like this:
template <class T>
class C;
template <class T, class U>
void func(C<T>& t);
template <class T>
class C
{
template <class U>
friend void func<T, U>(C<T>& t);
private:
template <class U>
void f()
{
}
};
template <class T, class U>
void func(C<T>& t)
{
t.f<U>();
}
But when I try to call func, I get a compilation error at the friend line:
'func': no matching overloaded function found
How can I make func<T, U> friend with C<T>?

The key issue is that the friend you declared, is not the same as the previous declaration you provided. The first expects two template parameters, but the second (friend) you defined to accept only one. Once that is resolved, everything works:
template <class T>
class C;
template <class U, class T>
void func(C<T>& t);
template <class T>
class C
{
template <class U, class TT>
friend void func(C<TT>& t);
private:
template <class U>
void f()
{
}
};
template <class U, class T>
void func(C<T>& t)
{
t.template f<U>();
}
int main() {
C<int> c;
func<bool>(c);
}
Watch it live.
Note I switched U and T up, because I assumed you may want T deduced and U explicitly specified.

Related

Passing object of a Templated struct to a member function of another templated class

I have a template class alpha_x give as,
template <typename T,typename U>
struct alpha_x {
const T & alpha;
const Scalar<U> & x;
alpha_x(const T & a_, const Scalar<U> & x_) : alpha(a_), x(x_) {};
};
I have another class with an overload for operator =
template <typename T>
class Scalar{
...
template <typename U,typename V>
const Scalar<T> & operator = (alpha_x<U,V> c);
...
}
When we try to define this function,
template <typename T,typename U,typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
//do something...
}
Now this gives an error "Too many template parameters in template redeclaration". How do I sort this out?
T template parameter is a class Scalar's template parameter. Thus it needs to be specified in a separate template parameter list.
Following would work:
template <typename T>
template <typename U, typename V>
const Scalar<T> & Scalar<T>::operator = (alpha_x<U,V> c){
// do something...
}

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.

How to declare a template function a friend of a templated nested class?

How can I make get a function in the enclosing scope that can access the private constructor of outer<T>::inner<U>?
template <typename T>
struct outer {
template <typename U>
class inner {
inner() {}
public:
friend inner get(outer&) {
return {};
}
};
};
int main() {
outer<int> foo;
outer<int>::inner<float> bar = get<float>(foo);
}
I have tried declaring it out of class by making inner have a template <typename V, typename W> friend inner<V> get(outer<W>&); but that didn't work either.
I have tried declaring it out of class by making inner have a template <typename V, typename W> friend inner<V> get(outer<W>&);
You need to declare the template function before the friend declaration, to tell the compiler that get is a template. E.g.
// definition of outer
template <typename T>
struct outer {
// forward declaration of inner
template <typename U>
class inner;
};
// declaration of get
template <typename V, typename W>
typename outer<W>::template inner<V> get(outer<W>&);
// definition of inner
template <typename T>
template <typename U>
class outer<T>::inner {
inner() {}
public:
// friend declaration for get<U, T>
friend inner<U> get<U>(outer<T>&);
};
// definition of get
template <typename V, typename W>
typename outer<W>::template inner<V> get(outer<W>&) {
return {};
}
LIVE

instanation of template function on template class

Given:
//hpp
template <typename T>
struct Demo {
template<typename U>
U convert(const T &t);
};
//cpp
template <typename T>
template <typename U>
U Demo<T>::convert(const T &t) {
return static_cast<U>(t);
}
how do I explicitly instantiate the template in the cpp? (e.g. T is double, U is int)
template int Demo<double>::convert<int>(const double &);

What's the legal syntax to define nested template?

I have the following nested template
class A {
template <typename T> class B {
template <typename U> void foo(U arg);
};
};
I am trying to define the nested template like so:
template <typename T, typename U> void
A::B<T>::foo(U arg) {...}
But am getting declaration is incompatible with function template error. What's the legal syntax to do so?
You need to separate the template declarations:
template <typename T>
template <typename U>
void
A::B<T>::foo(U arg) { … }