Making a Template Parameter a Friend

Making a template parameter a friend?

It is explicitly disallowed in the standard, even if some versions of VisualStudio do allow it.

C++ Standard 7.1.5.3 Elaborated type specifiers, paragraph 2

3.4.4 describes how name lookup proceeds for the identifier in an
elaborated-type-specifier. If the
identifier resolves to
a class-name or enum-name,
the elaborated-type-specifier introduces
it into the declaration the same
way a simple-type-specifier introduces
its type-name. If the identifier resolves
to a typedef-name or a
template type-parameter,
the elaborated-type-specifier is
ill-formed. [Note: this implies that,
within a class template with a
template type-parameter T, the
declaration friend class T; is
ill-formed. ]

I recognize the code above as a pattern to seal (disallow the extension of) a class. There is another solution, that does not really block the extension but that will flag unadvertidly extending from the class. As seen in ADOBE Source Library:

namespace adobe { namespace implementation {
template <class T>
class final
{
protected:
final() {}
};
}}
#define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>

with the usage:

class Sealed : ADOBE_FINAL( Sealed )
{//...
};

While it allows extension if you really force it:

class SealBreaker : public Sealed, ADOBE_FINAL( Sealed )
{
public:
SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {}
};

It will restrict users from mistakenly do it.

EDIT:

The upcoming C++11 standard does allow you to befriend a type argument with a slightly different syntax:

template <typename T>
class A {
// friend class T; // still incorrect: elaborate type specifier
friend T; // correct: simple specifier, note lack of "class"
};

Making an optional template parameter a friend?

I think befriending a dummy is the cleanest thing you can do, since you can't inherit or conditionally declare friends. You don't even need to create a new dummy type, since:

[class.friend§3]

If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored.

Which means that you can pretend to befriend int or even void and they'll play along just fine.

This advice is valid only within the limits of the C++ standard and is not intended as a real life guideline. The poster declines any and all responsibilities concerning the application of the advice.

Template parameter as a friend

From section §11.3, 3 in N3291:

template <typename T> class R {
friend T;
};

R<C> rc; // class C is a friend of R<C>
R<int> Ri; // OK: "friend int;" is ignored

So it is legal in C++11.

How do I make a template parameter's constructor a friend?

I was able to get it to compile in GCC by adding void after friend:

friend void T::T(const T&);

I was then able to access one of Test's private members from BeMyFriend's constructor. However, note that this is compiler specific. I tried it in clang, and it did not work.

Making a template parameter as friend of template class

The first thing is that as others mentioned friendship is not symmetric and you are attempting the wrong direction (granting A access to debugprinter<A>. That being said, and just for the sake of people searching through questions:

In the old version of the standard (C++03) it was impossible to directly declare a template argument as a friend. That restriction was lifted in C++11, although it requires a slightly different syntax:

template <typename T>
class test {
friend T; // note, not 'friend class T'!!!
};

Still, in C++03 you could achieve the same behavior by using one extra level of indirection. You cannot befriend a template argument, but you can befriend a dependent type, and by using an identity meta-function you could achieve what you wanted:

template <typename T>
struct identity {
typedef T type;
};
template <typename T>
class test {
friend class identity<T>::type;
};

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

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.

Template Friend Function of a Template Class (Friend with More Parameters)

Since there is an additional template parameter (compared to the template class parameters), it seems that one does not need to add the <> after the function name.
In conclusion, this worked fine for me:

template<std::size_t s, typename T>
class A;

template<std::size_t s, typename T, typename U>
A<s, T> operator *(U const lhs, A<s, T> const& rhs);

template<std::size_t s, typename T>
class A
{
// Blabla

template<typename U>
friend A<s, T> operator *(U const lhs, A<s, T> const& rhs);
};

template<std::size_t s, typename T, typename U>
A<s, T> operator *(U const lhs, A<s, T> const& rhs)
{
//BlaBla
}

C++: Correct syntax for friending a template type member of template parameter?

I don't think this is possible. From standard draft N4296:

§ 14.5.4/1 [temp.friend]

A friend of a class or class template can be a function template or class template, a specialization of a
function template or class template, or a non-template function or class.

This doesn't include alias templates, so the standard doesn't support what you want to do. This is perhaps due to the following excerpt (emphasis mine):

§ 14.5.7/1 [temp.alias]

A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to
be a alias template. An alias template is a name for a family of types.

An alias template names a separate family of types, so even if there were some syntax which made sense for this, you would be friending the alias template rather than the template which is being aliased.

For example, GCC will compile this (Clang won't), but you won't actually be able to use the friendship in any reasonable way:

template <bool B>
using MyTFoo = typename tTRAIT::template TFoo<B>;

template <bool> friend class MyTFoo;

Another example of how an alias template is not the same as the aliased template:

template <template <typename...> class A, template <typename...> class B>
struct is_same_template : std::false_type{};

template <template <typename...> class A>
struct is_same_template<A,A> : std::true_type{};

template <typename T> using myvec = std::vector<T>;

//this fails
static_assert(is_same_template<myvec,std::vector>::value, "wat");

Your manual friending with explicit instantiation will work, because the alias template will collapse down to exactly the same type as the aliased template. An analogous example:

//this passes!
static_assert(std::is_same<myvec<int>,std::vector<int>>::value, "wat");

Make all types passed as template-template argument a friend

A solution is to declare a common base class Wrapper as a friend of MyStruct and the wrap the private function. Declare xxx_TYPE as a derived class of this common class Wrapper.

template <typename T>
struct Wrapper {
void private_function(T* p) {
p->private_function();
}
protected:
Wrapper() = default;
};

template<typename MyStructType>
struct OTHER_SUB_TYPE: Wrapper<MyStructType> {
OTHER_SUB_TYPE(MyStructType* p) {
this->private_function(p);
}
// Need to access other private members of MyStructType
};

template<template<typename> class SUB_TYPE = DEFAULT_SUB_TYPE>
struct MyStruct {
SUB_TYPE<MyStruct> Get() { return SUB_TYPE{this}; }

template<typename T> friend struct Wrapper; // Wrapper as a friend class

private:
void private_function() {}
};

Demo



Related Topics



Leave a reply



Submit