problem with template friend partial specialization

Discussion in 'C++' started by Andrey Dj, Apr 2, 2012.

  1. Andrey Dj

    Andrey Dj Guest

    Hello!

    I found some interesting case of non-compiling C++ code.
    Look at first example:

    --------------------------------
    template<class T> void Foo(T*);
    class Bar;
    template<> void Foo(Bar*);

    class Bar
    {
    friend void ::Foo<>(Bar*);
    };
    --------------------------------

    Compiling... All fine.

    Now add to Foo return type of Baz:

    --------------------------------
    class Baz {};

    template<class T> Baz Foo(T*);
    class Bar;
    template<> Baz Foo(Bar*);

    class Bar
    {
    friend Baz ::Foo<>(Bar*);
    };
    --------------------------------

    Trying to compile:
    MSVC: error C2039: 'Foo' : is not a member of 'Baz'
    GCC: error: 'Foo' in class 'Baz' does not name a type

    Is there any way to declare such friend partial specialization?
     
    Andrey Dj, Apr 2, 2012
    #1
    1. Advertising

  2. On 4/2/2012 5:35 AM, Andrey Dj wrote:
    > Hello!
    >
    > I found some interesting case of non-compiling C++ code.
    > Look at first example:
    >
    > --------------------------------
    > template<class T> void Foo(T*);
    > class Bar;
    > template<> void Foo(Bar*);
    >
    > class Bar
    > {
    > friend void ::Foo<>(Bar*);
    > };
    > --------------------------------
    >
    > Compiling... All fine.
    >
    > Now add to Foo return type of Baz:
    >
    > --------------------------------
    > class Baz {};
    >
    > template<class T> Baz Foo(T*);
    > class Bar;
    > template<> Baz Foo(Bar*);
    >
    > class Bar
    > {
    > friend Baz ::Foo<>(Bar*);
    > };
    > --------------------------------
    >
    > Trying to compile:
    > MSVC: error C2039: 'Foo' : is not a member of 'Baz'
    > GCC: error: 'Foo' in class 'Baz' does not name a type
    >
    > Is there any way to declare such friend partial specialization?


    It's a tokenization problem, obviously. Your compiler treats the colons
    before 'Foo' in the friend declaration as part of an elaborate name
    specifier that starts with 'Baz'. It knows that 'Baz' is a class name...

    You could try adding a 'using' declaration before the 'friend':

    class Bar
    {
    using ::Foo;
    friend Baz Foo<>(Bar*);
    };

    (I've not tried it). Or you could put 'Baz' in parentheses:

    class Bar
    {
    friend (Baz) ::Foo<>(Bar*);
    };

    (I've not tried it either). What you essentially need is tell the
    compiler that the token "Baz" should stand on its own and not be treated
    as the beginning of an elaborate name specifier even though there is a
    name resolution operator after it.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Apr 3, 2012
    #2
    1. Advertising

  3. Victor Bazarov <> writes:

    > You could try adding a 'using' declaration before the 'friend':
    >
    > class Bar
    > {
    > using ::Foo;
    > friend Baz Foo<>(Bar*);
    > };
    >
    > (I've not tried it).


    GCC 4.6.3 doesn't like that.

    friend.cc:9:16: error: using-declaration for non-member at class scope

    > Or you could put 'Baz' in parentheses:
    >
    > class Bar
    > {
    > friend (Baz) ::Foo<>(Bar*);
    > };
    >
    > (I've not tried it either).


    That doesn't work either.

    friend.cc:9:16: error: ISO C++ forbids declaration of 'Baz' with no type [-fpermissive]
    friend.cc:9:16: error: 'Baz' is neither function nor member function; cannot be declared friend
    friend.cc:9:16: error: expected ';' at end of member declaration
    friend.cc:9:30: error: ISO C++ forbids declaration of 'Foo' with no type [-fpermissive]
    friend.cc:9:30: error: invalid use of '::'

    In general, you cannot put parentheses around types in
    declarations. For example, (int) x; does not declare a variable.
    Instead, put the parentheses around the name being declared, or
    around the whole declarator:

    class Baz {};

    template<class T> Baz Foo(T*);
    class Bar;
    template<> Baz Foo(Bar*);

    class Bar
    {
    friend Baz :):Foo<>)(Bar*);
    friend Baz :):Foo<>(Bar*)); /* same thing */
    };

    It seems one could also use a typedef, at least with GCC:

    class Bar
    {
    typedef Baz foofun(Bar*);
    friend foofun ::Foo<>;
    };

    However, I'm not sure how well that kind of friend declaration
    conforms to the standards, especially with the template argument
    deduction.
     
    Kalle Olavi Niemitalo, Apr 3, 2012
    #3
  4. Andrey Dj

    Andrey Dj Guest

    <b>Kalle Olavi Niemitalo</b>

    > class Bar
    > {
    > friend Baz :):Foo<>)(Bar*);
    > friend Baz :):Foo<>(Bar*)); /* same thing */
    > };


    Thank you very much, this works! :)
     
    Andrey Dj, Apr 5, 2012
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex@L
    Replies:
    6
    Views:
    482
    Mike Wahler
    Jan 20, 2005
  2. toton
    Replies:
    1
    Views:
    615
  3. Belebele
    Replies:
    3
    Views:
    456
    Victor Bazarov
    Nov 2, 2007
  4. vj
    Replies:
    1
    Views:
    484
  5. Hizo
    Replies:
    17
    Views:
    689
    itaj sherman
    Mar 7, 2011
Loading...

Share This Page