Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Befriending a template template parameter

I've got a class template with a template template parameter, and I want to declare this parameter (that is, all of its specializations) as a friend. But I can't find the correct syntax.

template <template <class> class T>
struct Foo {

    template <class U>
    friend T;           // "C++ requires a type specifier for all declarations"

    template <class U>
    friend struct T;    // "declaration of 'T' shadows template parameter"

    template <class U>
    friend struct T<U>; // "cannot specialize a template template parameter"

    pretty<please>
    lets(be) friends T; // Compiler shook its standard output in pity
};

How can I declare a template template parameter as friend?

Coliru snippet

like image 761
Quentin Avatar asked Mar 16 '17 23:03

Quentin


People also ask

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.

What is correct for template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

Can a template class be a friend?

One-to-one: A template function instantiated with one set of template arguments may be a friend to one template class instantiated with the same set of template arguments. This is also the relationship between a regular non-template class and a regular non-template friend function.


1 Answers

I've found this problem is very interesting to research. According to standard (C++11 and above) this should works fine, I guess:

template <template <class> class U>
struct identity {
    template <typename T>
    using type = U<T>;
};

template <template <class> class U>
struct Foo {
    template <typename>
    friend class identity<U>::type;
};

Due to one indirection level, there are no any shadowing and name reusing here, and this situation described as following:

cppreference:

Both function template and class template declarations may appear with the friend specifier in any non-local class or class template (...). In this case, every specialization of the template becomes a friend, whether it is implicitly instantiated, partially specialized, or explicitly specialized. Example: class A { template<typename> friend class B; }

However, it seems like clang and MSVC think otherwise: see coliru or godbolt. Moreover, their error messages seem meaningless, so it looks like a compiler bug (or just an incorrectly detected syntax error). GCC compiles and executes mentioned snippets perfectly, but I still not sure it's a correct solution.

like image 60
Trollliar Avatar answered Oct 03 '22 05:10

Trollliar