29

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

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • 1
    I don't have an answer, but here are some references: [CWG585](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#585) - considered not a defect, although I really don't know what the rationale is supposed to mean. Also, [this GCC patch](https://gcc.gnu.org/ml/gcc-patches/2011-05/msg02115.html); GCC indeed accepts `template friend class T;`, which Clang and EDG reject (MSVC doesn't reject it outright, but it doesn't seem to do something useful with it either). – bogdan Mar 17 '17 at 01:17
  • 1
    The third form is disallowed by [\[temp.friend\]/7](http://eel.is/c++draft/temp.friend#7). – Columbo Mar 17 '17 at 03:05
  • 6
    I'm not sure what you are trying to express, but maybe this will work?`template class T> struct Foo { friend T; };` – Michael Nastenko Mar 17 '17 at 06:39
  • @bogdan: it looks like the rationale's example is directly at odds with Columbo's standard quote. What is going on here? – Quentin Mar 17 '17 at 08:54
  • 3
    Indeed, and I agree about that form being invalid under the current wording (`T` is a partial specialization according to [\[temp.class.spec\]/1](http://eel.is/c++draft/temp.class.spec#1), although an invalid one because it's not more specialized than the primary). I would expect the correct form to be either the first one in your example or simply `friend T;`, as in the proposed resolution of CWG585, to keep it consistent with non-template template parameters. It looks like what's going on is, in very strict standard terms, *a mess*. – bogdan Mar 17 '17 at 10:09
  • @bogdan My particular use case will work fine without that, but... Is there something I can do? – Quentin Mar 17 '17 at 11:10
  • 1
    I was going to say "let's ask on std-discussion", but Brian Bi [has already done that](https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/b5fjqkdqLfE) and referenced your question, so let's see how that goes. – bogdan Mar 17 '17 at 17:43
  • 7
    can someone please submit the `pretty lets(be) friends T;` syntax for standards approval. – sp2danny May 05 '17 at 12:49
  • Can you give an example of why this would be useful? I think what you're asking for is fundamentally flawed. – atoMerz May 26 '17 at 14:18

2 Answers2

1

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.

Community
  • 1
  • 1
Trollliar
  • 826
  • 5
  • 14
  • Wow, this looks mighty weird -- I don't know how template argument deduction and friend declarations interact, but I'm surprised that this works through a non-deduced context. +1 nonetheless, this looks like valuable information :) – Quentin Jun 06 '17 at 14:20
-2

Templates tend to get programmers to over-complicate things. I'm not exactly sure what you are trying to do, and I suspect that there is probably a better way to do it, but this should work.

template <template <class> class T, class U>
class Foo {
    friend class T<U>;
};
ventsyv
  • 3,316
  • 3
  • 27
  • 49