A<T> 的朋友可以也是 A<A<T>> 的朋友吗?
Can a friend of A<T> be also a friend of 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_container
是 Container<T>
的朋友,但不是 Container<Container<T>>
的朋友。我怎样才能让 make_double_container
在这种情况下工作?
将 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
是什么时,它会实例化 class 并将具有类型名称 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>>>&);
然后(在 main 内)进入
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
显然,您可以将 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.
考虑以下代码:
#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_container
是 Container<T>
的朋友,但不是 Container<Container<T>>
的朋友。我怎样才能让 make_double_container
在这种情况下工作?
将 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
是什么时,它会实例化 class 并将具有类型名称 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>>>&);
然后(在 main 内)进入
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
显然,您可以将 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.