2015-11-01 10 views
14

Betrachten Sie den folgenden Code ein:Kann ein Freund von A <T> auch ein Freund von A <A<T>> sein?

#include <vector> 

template<typename T> class Container; 
template<typename T> Container<Container<T>> make_double_container(const std::vector<std::vector<T>>&); 

template<typename T> 
class Container { 
    std::vector<T> v; 
    friend Container<Container<T>> make_double_container<T>(const std::vector<std::vector<T>>&); 

public: 
    Container() {} 
    explicit Container(std::vector<T> v) : v(v) {} 
}; 

template<typename T> 
Container<Container<T>> make_double_container(const std::vector<std::vector<T>>& v) { 
    Container<Container<T>> c; 
    for(const auto& x : v) { 
     c.v.push_back(Container<T>(x)); 
    } 
    return c; 
} 

int main() { 
    std::vector<std::vector<int>> v{{1,2,3},{4,5,6}}; 
    auto c = make_double_container(v); 
    return 0; 
} 

Der Compiler sagt mir, dass:

main.cpp: In instantiation of 'Container<Container<T> > make_double_container(const std::vector<std::vector<T> >&) [with T = int]': 
main.cpp:27:37: required from here 
main.cpp:8:20: error: 'std::vector<Container<int>, std::allocator<Container<int> > > Container<Container<int> >::v' is private 
    std::vector<T> v; 
        ^
main.cpp:20:9: error: within this context 
     c.v.push_back(Container<T>(x)); 

die ich glaube, richtig zu sein, weil make_double_container ist der Freund von Container<T>, aber nicht von Container<Container<T>>. Wie kann ich make_double_container in dieser Situation arbeiten lassen?

+1

Frage ist theoretisch interessant. Aber Vektoren von Vektoren sind, irgendwie, böse, so dass es meistens den Zweck verfehlt. – Drop

Antwort

10

klar ist, können Sie jede Spezialisierung von make_double_container machen einen Freund:

template <typename U> 
friend Container<Container<U>> make_double_container(const std::vector<std::vector<U>>&); 

Wenn Sie Freundschaft auf ein Minimum ohne partielle Spezialisierung oder dergleichen zu halten, versuchen

template <typename> struct extract {using type=void;}; 
template <typename U> struct extract<Container<U>> {using type=U;}; 
friend Container<Container<typename extract<T>::type>> 
    make_double_container(const std::vector<std::vector<typename extract<T>::type>>&); 

Demo.

+0

Ich wollte genau vermeiden 'f ' werden Freund von 'A ' (erste Code-Snippet). Ich denke, dass Ihr zweiter Code-Ausschnitt eine "präzise" Freundschaft schafft, während Sie den Aufwand vermeiden, viele spezialisierte 'f's zu schreiben. Cleverer Trick, +1! –

3

Definieren make_double_container als Vorlage Funktion von S scheint es zu kompilieren und zu arbeiten.

template<typename T> 
class Container { 
    std::vector<T> v; 

    template<class S> 
    friend Container<Container<S>> make_double_container(const std::vector<std::vector<S>>&); 

public: 
    Container() {} 
    explicit Container(std::vector<T> v) : v(v) {} 
}; 

http://coliru.stacked-crooked.com/a/bdc23a0451a2125b

, wenn der Compiler etwas in der Struktur sieht:

template<class T> 
class X{}; 

, wenn Sie angeben, was T ist, instanciates es die Klasse und ersetzt alles mit dem Typnamen T mit dem angegebenen Art.

, wenn Sie schreiben

Container<Container<T>> c; 

T ist in der Tat Container<T> und make_double_container turnes in

Container<Container<Container<T>>> make_double_container(const std::vector<std::vector<Container<T>>>&); 

und dann (im Haupt) in

Container<Container<Container<int>>> make_double_container(const std::vector<std::vector<Container<int>>>&); 

durch die Freundschaft verwandelt sich in :

template<class S> 
    friend Container<Container<S>> make_double_container(const std::vector<std::vector<S>>&); 

Sie den Compiler zwingen, um herauszufinden, was S aus der Vorlage von Container<Container<T>> ist, und dann rechnet sie die richtige Art von S aus, die int

+0

Ihre Lösung würde funktionieren, aber es würde z.B. 'make_double_container ' ein Freund von 'Container >'. –

+0

sollte es tun. –

Verwandte Themen