https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64596

            Bug ID: 64596
           Summary: Friendship not recognized and template param deduction
                    error
           Product: gcc
           Version: 5.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: petschy at gmail dot com

Explanation of the attached code: Str is a stream class, Txn is its helper,
thus needs access to Str's private members. There is also a Glue class that is
supposed to glue together a stream implementation and the streamed type. This
way the streamed type needs to grant friend access only to Glue, and need not /
should not know about the streams. The stream might also grant friendship to
Glue. For a specific stream type and streamed type Glue should be specialized
and perform the actual streaming there, optionally using the private members of
the stream and the streamed type.

Implementing this I ran into two errors and though I have a workaround, it's
not clear to me that the errors are due to some strange interaction of the
language rules, or bugs in the compiler.

Plan A: the Txn class is separate from Str. Str wants to grant friendship to
Txn, but with the same E type only. template<bool R> friend class Txn<E,R>;
won't work as the compiler sees this as a specialization. To work around this I
used a templated using directive: template<bool R> using Tx = Txn<E,R>; and
granted friendship to Tx. Unfortunately this doesn't work, when Txn tries to
access the private member i, an error is reported.

Plan B: move Txn inside StrB. This solves the access problem, but then there's
a new error: the Glue specialization won't compile, telling me that the
template params cannot be deduced. This is strange, as the syntax is the same
as in Plan A.

Plan C: move Txn inside StrC, but create TxnC, a simple forwarder class
outside, too. This way the access works, since Txn is inside, and the Glue
specialization works since we glue the outside class, TxnC. However, this is
tedious with real code.

Tested with 4.9.1 and 5.0 (20141222), both give the same errors:

g++ -std=c++11 -Wall 20150114-friend.cpp 
20150114-friend.cpp:81:8: error: template parameters not deducible in partial
specialization:
 struct Glue<StrBTxn<E, R>, int> // error: template parameters not deducible in
partial specialization
        ^
20150114-friend.cpp:81:8: note:         ‘E’
20150114-friend.cpp: In instantiation of ‘Txn<E, R>::Txn(Txn<E, R>::S&) [with E
= int; bool R = false; Txn<E, R>::S = Str<int>]’:
20150114-friend.cpp:45:38:   required from ‘static void Glue<Txn<E, R>,
int>::Foo() [with E = int; bool R = false]’
20150114-friend.cpp:52:30:   required from here
20150114-friend.cpp:17:6: error: ‘int Str<int>::i’ is private
  int i;
      ^
20150114-friend.cpp:28:3: error: within this context
   ++s.i; // error: ‘int Str<int>::i’ is private
   ^

Reply via email to