2016-07-15 11 views
0

Ich stehe vor einer Situation, aus der zwei Fragen zur Funktionsweise von ADL und Template-Funktionen unter bestimmten Umständen auftauchen.Explizite Freundesspezialisierung der Template-Funktion in der Klassenvorlage

  1. Warum kann ich nicht verwenden cout innerhalb Freund Spezialisierung Definition? in diesem Szenario Ich erhalte einen Link-Fehler, der besagt, dass basic_stream ist undefiniert, aber wenn ich auf cat aufrufen, die Kompilierung fortfahren.

    template<class T> 
    void func1(T&){ 
        ... 
    } 
    
    void cat(){ cout << "foo.func1" <<endl; } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<int>&){ 
          cout << "foo.func1" <<endl; // cat(); 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f); 
    
  2. Warum ADL gilt nicht, wenn ich die Spezialisierung ändern, um eine Template-Klasse param zu verweisen? Wenn ich nicht falsch mit ADL-Mechanik, um die richtige Version von func1 aufzurufenden 3 (zB global (1), oder Freund definiert eine (2)), sammelt es alle möglichen Übereinstimmungen und wählt die konkreteste ein. und ich denke, die konkreteste ist die Version von func1 in 2, weil, anstatt die Funktion param als vollständig abhängig von der Vorlage param, geben Sie einen konkreten Typ foo, die func1 in 1 nicht, sondern ADL wählen func1 in 1 sowieso. Warum das ?

    template<class T> 
    void func1(T&){  // 1 
        ... 
    } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<R>&){  // 2 
          cout << "foo.func1" <<endl; 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f);  // 3 
    
+0

Meinen Sie 'erste :: foo f; '? – aschepler

+0

Ich glaube nicht, dass dieser Code gültig ist. Ich bekomme "Fehler: Definieren der expliziten Spezialisierung 'func1' in der Friend-Deklaration". http://coliru.stacked-crooked.com/a/728b83afb9b416a4 – aschepler

+0

Der Code sollte nicht kompilieren, welchen Compiler verwenden Sie? – Barry

Antwort

1

sind Template-Parameter mit Freund Erklärungen unabhängig. Sie finden sie in der friend Erklärung vereindeutigt tragen müssen:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void func1<U>(foo<U>&){ 
     cout << "foo.func1" <<endl; // cat(); 
    }   
};  

auch für Ihren Fall sollten Sie sich entscheiden, wenn Sie wie oben den Freund Definition inlined setzen wollen, oder bieten nur eine Erklärung:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void ::func1<U>(foo<U>&); 
};  

letztere sollten die friend Template-Funktion im globalen Namespace explizit übereinstimmen, und Spezialisierung kann je nach Bedarf vorgenommen werden:

template<> 
void func1(int&){ 
    // ... 
} 

template<> 
void func1(std::string&){ 
    // ... 
} 

// a.s.o. 
+0

Ich glaube, dein erstes Beispiel ist schlecht geformt, ndr. – Barry

+0

Thank's, Freund Deklaration Params von der Vorlage Klasse param trennen macht es funktioniert. – xhamr

+0

@Barry, ja es ist teilweise, aber das Ändern des Teils "func1 " zu "func1" und das Verlassen der anderen Teile wie es ist, beheben Sie das Problem "keine teilweise Spezialisierung Fehler" ist das, was Sie beziehen. – xhamr

1

Sie müssen keine Spezialisierung func1 angeben. Geben Sie einfach eine Überlastung:

namespace first { 
    template <class R> 
    struct foo { 
     friend void func1(foo&){ 
      std::cout << "foo.func1" << std::endl; 
     } 
    }; 
} 

int i; 
first::foo<int> f; 

func(i); // calls ::func<int> 
func1(f); // calls first::func1(first::foo<int>&); 

Andernfalls Sie Freund ein specizliation können, aber Sie können eine Spezialisierung in der Klasse Körper nicht definieren:

template <class R> 
struct foo { 
    friend void func1<>(foo&); // friends ::func1<foo<R> > 
}; 
+0

"aber Sie können keine Spezialisierung im Klassenkörper definieren"[email protected] Wenn Sie in das erste Szenario schauen, wird die Spezialisierung mit foo & anstelle von foo & gemacht und die Kompilierung scheitert, weil es beim Verknüpfen "cout" nicht finden kann, aber stattdessen verwenden Sie "printf" die Kompilierung erfolgreich und Freund Spezialisierung gewählt. – xhamr

+0

@xhamr 1) Das ist kein Fehler beim Kompilieren, das ist ein Linker-Fehler 2) Der Code sollte aufgrund der expliziten Spezialisierung nicht kompilieren ... oder zumindest ODR-Probleme haben. Einfacher zu überladen. – Barry

+0

@xhamr Sorry, muss nicht kompilieren fehlschlagen. Siehe [\ [temp.expl.spec \]] (http://eel.is/c++draft/temp.expl.spec#6). – Barry