2015-01-17 26 views
11

Dlaczego kod poniżej dobrze skompilowany w g ++, ale pojawia się błąd na klang?clang/g ++ różnica z funkcją znajomego

#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; 
} 

linki Dowód: g++/clang++

Kiedy przeniósł przyjaciela funkcję do globalnej przestrzeni nazw, dobrze skompilowany kod dla obu kompilatorów (clang++/g++).

Które wdrożenie w tym przypadku jest bardziej zgodne ze standardami C++?

+0

Clang jest prawdopodobnie poprawne. Myślę, że jest to możliwy duplikat http: // stackoverflow.com/q/15745776/2073257 –

+0

@DanielFrey w moim przypadku nawet ja usunąłem szablon i otrzymałem ten sam błąd: http://coliru.stacked-crooked.com/a/765458742bfcea4d – alexolut

+4

N.B. GCC 5.0 odrzuca twój przykład. Myślę, że to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59366, którego naprawa została popełniona dwa dni temu. –

Odpowiedz

9

Clang jest tutaj poprawny. Funkcje przyjaciół zdefiniowane w klasach można znaleźć tylko przy użyciu argumentów, które są zależne od argumentów, a nie zwykłego wyszukiwania. Ponieważ Print nie jest powiązanym zakresem do Object, nie należy znaleźć operator<<. Częściowe cytat z normą:

7.3.1.2 definicji użytkownika nazw [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).

jako @sehe wymienia właściwy sposób dodaj operator<< do Object jest to określić jako funkcja globalna (przy użyciu interfejsu Object) lub jako funkcja friend w sobie (przy użyciu funkcji private z Object), a nie w niektórych klasach pomocniczych. Zobacz także stara kolumna Herb Sutter: "What's in a class?"

4

Najgorsza rzecz to zadeklarowanie statycznego (znajomego) operatora w klasie innej klasy (która nie ma związku).

  1. Można po prostu utworzyć go w otaczającym zakresie, nie

    • bez różnicy semantycznie
    • ma powodu, aby mieć go znajomym (jak Printer nie jest stosowany w dowolny sposób)
    • ty może nadal być przyjacielem, jeśli musisz

    Live On Coliru

  2. Alternatywnie aby inna klasa związane;

    Istnieje wiele sposobów na powiązanie przestrzeni nazw (§3.4.2) z typem do wyszukiwania funkcji. Na przykład ten siekać będzie wystarczających do kojarzenia nazw Print klasy z typem Object tak ADL nadal działa:

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

    Zobacz ten Live On Coliru także

+0

Alternatywnie, powiąż przestrzeń nazw 'Print' z typem" Object ", aby funkcja ADL nadal działała: ** [Live On Coliru] (http://coliru.stacked-crooked.com/a/2f3aac5a030efa86) ** – sehe

+0

Jak to działa? hackowanie # 2? – 0x499602D2

+0

@ 0x499602D2 ADL wyszukuje niekwalifikowane bezpłatne funkcje we wszystkich przestrzeniach nazw powiązanych z typami argumentów. "Powiązane przestrzenie nazw" obejmuje te, które deklarują typy argumentów szablonu. – sehe

Powiązane problemy