clang/g++ difference with friend function
Asked Answered
N

2

12

Why code below well compiled in g++ but get error on clang?

#include <iostream>

class Object {};

class Print
{
public:
    template <typename CharT>
    inline friend std::basic_ostream<CharT> & operator<<(std::basic_ostream<CharT> & out, const Object&)
    {
        return (out << "object");
    }
    static void f( const Object& str )
    {
        std::cout << str;
    }
};

int main()
{
    std::cout << Object() << std::endl;
    return 0;
}

Proof links: g++ / clang++

When I moved friend function to global namespace, code well compiled for both compilers (clang++ / g++).

Which implementation in this case is more C++ Standart compatible?

Naman answered 17/1, 2015 at 19:42 Comment(4)
Clang is probably correct. I think this is a possible duplicate of https://mcmap.net/q/1010125/-templated-friend-function-lookup/2073257Bate
@DanielFrey in my case even I remove template i got same error: coliru.stacked-crooked.com/a/765458742bfcea4dHalfon
N.B. GCC 5.0 rejects your example. I think this is gcc.gnu.org/bugzilla/show_bug.cgi?id=59366 which had a fix committed two days agoBove
Xeo's comment on the linked question is the explanation (independent of the template), as also backed up by @TemplateRex's quote from the standard in his answer to this question.Bate
A
9

Clang is correct here. Friend functions defined inside classes can only be found using argument-dependent-lookup on their arguments, not by ordinary lookup. Because Print is not an associated scope to Object, the operator<< should not be found. Partial quote from the Standard:

7.3.1.2 Namespace member definitions [namespace.memdef]

3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template97 the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ] If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2).

As @sehe mentions, the proper way to add an operator<< to Object is to define it as a global function (using Object interface) or as a friend function inside itself (using private functions from Object), not in some auxiliary class. See also Herb Sutter's old GotW column "What's in a class?"

Agadir answered 17/1, 2015 at 20:7 Comment(0)
R
4

The iffy thing is to declare an static (friend) operator in another class (that is unrelated).

  1. You could just create it in the surrounding scope, there's

    • no difference semantically
    • no reason to have it a friend (as Printer is not used any way)
    • you can still make it a friend if you needed to

    Live On Coliru

  2. Alternatively, make the other class related;

    There are many ways to associate namespaces (§3.4.2) with a type for function lookup. For example this hack would be enought to associate the Print class namespace with the Object type so ADL will still work:

    template <typename> struct Object_ {};
    typedef Object_<class Print> Object;
    

    See this Live On Coliru as well

Resolutive answered 17/1, 2015 at 20:8 Comment(4)
Alternatively, associate the Print class namespace with your Object type so ADL still works: Live On ColiruResolutive
@0x499602D2 ADL looks up unqualified free functions in all namespaces associated with the argument types. "Associated namespaces" includes those declaring the template argument types.Resolutive
So the compiler looks at the associated namespaces of the template arguments? Woah, just learned something new!Superadd
Let us continue this discussion in chat.Resolutive

© 2022 - 2024 — McMap. All rights reserved.