2015-11-01 66 views
14

考慮下面的代碼:A <T>的朋友也可以A <A<T>>的朋友嗎?

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

編譯器告訴我說:

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)); 

我相信這是正確的,因爲make_double_containerContainer<T>的朋友,但不是Container<Container<T>>。我該如何讓make_double_container在這種情況下工作?

+1

問題在理論上是有趣的。但是載體的載體是邪惡的,所以它主要是擊敗了目的。 – Drop

回答

10

很明顯,你可以使make_double_container一個每專業化朋友:

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

如果你想保持友誼,沒有偏特之類最低限度,儘量

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

我確實想避免'f '成爲'A '(第一個代碼片段)的朋友。我認爲你的第二個代碼片段提供了「精確」的友誼,同時避免了編寫許多專用的「f」的麻煩。聰明的伎倆,+1! –

3

定義make_double_container作爲S的模板函數似乎使其編譯和工作。

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

當編譯器看見東西的結構:

template<class T> 
class X{}; 

當你指定什麼T,它instanciates類,並與類型名T取代一切規定類型。

當你寫

Container<Container<T>> c; 

T其實Container<T>,並make_double_container地調進

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

,然後(內部主)到

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

通過改變友情的:

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

你強制編譯器弄清楚什麼是從Container<Container<T>>模板S,然後計算出正確類型的S,這是int

+0

您的解決方案可行,但它會使例如'make_double_container ''Container >'的朋友。 –

+0

它應該這樣做。 –