2015-11-01 65 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

它应该这样做。 –