Template factory function with additional args: friendship issue - c++

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

Related

Is there a way to use hidden friends when using (recursive) constraints?

Suppose one has a class for which one wants to define hidden friends, e.g. heterogeneous comparison operators:
#include <concepts>
template <typename T> struct S;
template <typename C> constexpr bool is_S = false;
template <typename T> constexpr bool is_S<S<T>> = true;
template <typename T>
struct S {
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
template <typename U>
requires
(!is_S<U>) && std::equality_comparable_with<T, U>
friend constexpr bool operator==(const S &s, const U &u) { return s.data == u; }
};
// pre-existing, not hidden friend
template <typename T>
constexpr bool operator==(const S<T> &a, const S<T> &b) { return a.data == b.data; }
The code above seems reasonable, but it doesn't work due to CWG2369's resolution -- which at the moment is only implemented by GCC (>=11). The resolution make the constraint resolution have endless recursion, for instance when using something like this:
template <typename T>
struct wrapper
{
T value;
};
template <typename T, typename U>
requires std::equality_comparable_with <T, U>
constexpr bool operator==(const wrapper<T>& a, const wrapper<U>& b)
{
return a.value == b.value;
}
using SD = S<double>;
static_assert(std::equality_comparable<wrapper<SD>>); // ERROR, recursive constraints
The solution in this case should be to constrain S's operator== in a non-dependent way:
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
But now this does not depend on a specific S specialization any more, and therefore will cause redefinition errors:
S<int> s1;
S<double> s2; // ERROR: redefinition of operator==
(Godbolt for all of the above.)
Am I missing something or the above solution for the recursive constraints is fundamentally incompatible with hidden friends?
Here's a possible solution: defining the operator in a non-template empty base class:
class S_base
{
template <typename V, typename U>
requires
is_S<V> && (!is_S<U>) && std::equality_comparable_with<typename V::type, U>
friend constexpr bool operator==(const V &v, const U &u) { return v.data == u; }
};
Then have S privately inherit from it:
template <typename T>
struct S : private S_base
{
using type = T;
T data;
constexpr S() : data() {}
constexpr explicit S(const T &t) : data(t) {}
};
Many thanks to Patrick Palka for suggesting this approach.

Meta-iteration over variadic templates arguments

I would like to generalize the following pattern:
template<class A1, class A2, class A3>
class Foo {
protected:
template<class T>
void foo(const T& t) {...do stuff...}
public:
void bar(const A1& a) { foo(a); }
void bar(const A2& a) { foo(a); }
void bar(const A3& a) { foo(a); }
};
The above approach does not scale with a number of increasing arguments. So, I'd like to do:
template<class As...>
class Foo {
protected:
template<class T>
void foo(const t& a) {...do stuff...}
public:
for each type A in As declare:
void bar(const A& a) { foo(a); }
};
Is there a way to do it?
another approach could be to have a check in bar to test if the type is in the sequence, else barf with a useful error message, this avoid any inheritance tricks..
#include <iostream>
struct E {};
struct F {};
template <class... As>
class Foo
{
template <typename U>
static constexpr bool contains() {
return false;
}
template <typename U, typename B, typename ...S>
static constexpr bool contains() {
return (std::is_same<U, B>::value)? true : contains<U, S...>();
}
protected:
template <class T>
void foo(const T& a) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
public:
template <class T>
void bar(const T& a) {
static_assert(contains<T, As...>(), "Type does not exist");
foo(a);
}
};
int main()
{
Foo<E, F, E, F> f;
f.bar(F{});
f.bar(E{});
f.bar(1); // will hit static_assert
}
In case you don't actually need the bars and instead just need to constrain foo - we can use SFINAE to allow a call to it only with a type convertible to one of the As:
template <class... As>
class Foo {
public:
template <class T,
class = std::enable_if_t<any<std::is_convertible<T, As>::value...>::value>>
void foo(T const&) { ... }
};
Where we can implement any with something like the bool_pack trick:
template <bool... b> struct bool_pack { };
template <bool... b>
using any = std::integral_constant<bool,
!std::is_same<bool_pack<b..., false>, bool_pack<false, b...>>::value>;
template <class CRTP, class A, class... As>
struct FooBar
{
void bar(const A& a)
{
static_cast<CRTP*>(this)->foo(a);
}
};
template <class CRTP, class A, class B, class... As>
struct FooBar<CRTP, A, B, As...> : FooBar<CRTP, B, As...>
{
using FooBar<CRTP, B, As...>::bar;
void bar(const A& a)
{
static_cast<CRTP*>(this)->foo(a);
}
};
template <class... As>
class Foo : FooBar<Foo<As...>, As...>
{
template <class, class, class...>
friend struct FooBar;
protected:
template <class T>
void foo(const T& a) { }
public:
using FooBar<Foo, As...>::bar;
};
DEMO
template <class A, class... As>
class Foo : public Foo<As...>
{
protected:
using Foo<As...>::foo;
public:
using Foo<As...>::bar;
void bar(const A& a) { foo(a); }
};
template <class A>
class Foo<A>
{
protected:
template <class T>
void foo(const T& t) { }
public:
void bar(const A& a) { foo(a); }
};
In a similar vain to Piotr Skotnicki's answer, this uses inheritance to build up a class with bar overloads for all of the template arguments. It's a bit cleaner though, with only one class template plus a partial specialization.
template<class A, class Foo_t>
class bar_t {
public:
void bar(const A &a) { Foo_t::foo(a); }
};
template<class ...As>
class Foo : bar_t<As, Foo<As...> >... {
protected:
template<class T>
void foo(const T& a) { /* do stuff */ }
};

Template Friending syntax

Say I have two Template classes.
template<class T>
class baseclass1
{
template<class> friend class baseclass2;
}
template<class D>
class baseclass2
{
template<class T> void foo( D& x, T& y)
{
...
}
}
The Above code allows all types of baseclass1 to friend all types of baseclass2, a many-to-many relationship. I have two questions,
What is the syntax to allow baseclass1 to friend just the function
baseclass2<class D>::foo<class T>( D& x, T& y).
And, what is the syntax to allow baseclass1 to friend just the function
baseclass2<class D>::foo<class T>( D& x, T& y) where T from baseclass1 matches The T from Function foo.
EDIT
To those who keep claiming you can't friend a template specialization. This code works
template<class cake>
class foo
{
public:
static void bar(cake x)
{
cout << x.x;
}
};
class pie
{
public:
void set( int y){ x = y; }
private:
int x;
friend void foo<pie>::bar(pie x);
};
class muffin
{
public:
void set( int y){ x = y; }
private:
int x;
friend void foo<pie>::bar(pie x);
};
int main
{
pie x;
x.set(5);
foo<pie>::bar(x);
muffin y;
y.set(5);
//foo<muffin>::foo(y); //Causes a compilation Error because I only friended the pie specialization
}
Even notice where muffin friends the wrong foo, and still causes a compilation error. This works with both functions and classes. I am totally willing to accept that this isn't possible in my specific situation (It's actually looking more and more that way) I'd just like to understand why.
Befriending all possible specializations of baseclass2<D>::foo is rather easy:
template<class T> class baseclass1;
template<class D>
class baseclass2{
public:
template<class T>
void foo(D&, T&){ baseclass1<T> x; x.priv_foo(); }
};
template<class T>
class baseclass1{
template<class D>
template<class U>
friend void baseclass2<D>::foo(D&, U&);
void priv_foo(){}
};
template<class T>
class baseclass1{
template<class D>
template<class U>
friend void baseclass2<D>::foo(D&, U&);
};
Live example.
A forward declaration of baseclass2 (so baseclass1 knows that baseclass2 exists and is a template) and two templates, one for the class, one for the function. It also looks like this for out-of-class definitions for function templates of class templates. :)
Befriending specifically baseclass2<D>::foo<T> is not possible, however, or I can't find
the correct syntax for it.
A workaround might be some global function that forwards the access and together with the passkey pattern, but meh, it's a mess (imho):
template<class D> class baseclass2;
template<class D, class T>
void baseclass2_foo(baseclass2<D>& b, D&, T&);
template<class D, class T>
class baseclass2_foo_key{
baseclass2_foo_key(){} // private ctor
friend void baseclass2_foo<>(baseclass2<D>&, D&, T&);
};
template<class T>
class baseclass1{
public: // public access, but only baseclass2_foo can create the key
template<class D>
void priv_foo(baseclass2_foo_key<D, T> const&){}
};
template<class D, class T>
void baseclass2_foo(baseclass2<D>&, D&, T&){
baseclass1<T> x;
x.priv_foo(baseclass2_foo_key<D, T>());
}
template<class D>
class baseclass2{
public:
template<class T>
void foo(D& d, T& t){ baseclass2_foo(*this, d, t); }
};
Live example.
AFAIK you may specify all instantiation of foo as friend but not an specific instantiation:
template< class T >
class C1 {
public:
template< class Q > void foo( T& x, Q& y ) {
}
};
template< class T >
class C2 {
template< class Y >
template< class Q > friend void C1<Y>::foo( Y&, Q& );
};

How do you define a nested templated class' method outside of the class declaration?

How do I define func outside of the class declaration, below class A{...};?
template<typename T>
class A
{
template<typename Q>
class B
{
static void func(const A<T>& a){} // How do I define this function outside of the class declaration?
};
};
With a double template:
template<typename T>
template<typename Q>
void A<T>::B<Q>::func(const A<T>& a)
{
}
It's fairly straight-forward:
template<typename T>
template<typename Q>
void A<T>::B<Q>::func(const A<T>& a) { }
Basically it's the same technique as defining a templated class method outside the declaration of a class template. For instance:
template<typename T>
class test
{
template<typename U>
void func(const U& u);
};
You would define func outside the class like so:
template<typename T>
template<typename U>
void test<T>::func(const U& u) { }

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