如何定义在两个 class 之外的模板 class 内部的非模板 class 中声明的友元函数?
How to define a friend function declared in a non template class internal to a template class outside of both classes?
我找到了 "how to define a friend template function of a template class outside of its declaration" (SO/cppreference),但是如果我们在组合中添加另一个内部非模板 class 怎么办?
即如何(外部)定义在 class Internal
中声明的 operator<<
来自以下示例:
#include <iostream>
template <typename T>
class External {
public:
explicit External(T initial) : value{initial} {}
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
friend std::ostream& operator<<(std::ostream& os, const Internal& i);
// ^^^ this one
/* body
{
return os << i.internal_value;
}
*/
T internal_value;
};
friend std::ostream& operator<<(std::ostream& os, const External& e)
{
return os << Internal{e};
}
private:
T value;
};
int main()
{
std::cout << External<int>{5};
}
问题来了。尽管 External
是模板而 Internal
是依赖类型。 friend 函数本身不是模板化的。看起来很奇怪,它不依赖于模板参数。
当您内联定义它时,模板的每个特化也会创建关联的友元函数。但是当它不是内联时,你需要为每个特化显式提供运算符的定义。你不能用模板来做,因为函数不是模板。
因此,如果您在模板声明之后添加:
std::ostream& operator<<(std::ostream& os, External<int>::Internal const& i)
{
return os << i.internal_value;
}
它将构建。如您所见,函数中只使用了具体类型。
显然这不是一个很好的解决方案。任何明智的人都希望 External
的特化来生成朋友定义。以可维护的方式实现这一点的方法是保持运算符定义 内联 ,但不是在那里做工作,而是委托给成员函数( 是 取决于模板参数):
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
std::ostream& print(std::ostream&) const;
friend std::ostream& operator<<(std::ostream& os, Internal const& i)
{
return i.print(os); // Short and sweet on account of being inline
}
T internal_value;
};
//....
template<typename T>
std::ostream& External<T>::Internal::print(std::ostream& os) const {
// Provided outside of the class definition, can be as verbose as you like
return os << internal_value;
}
我找到了 "how to define a friend template function of a template class outside of its declaration" (SO/cppreference),但是如果我们在组合中添加另一个内部非模板 class 怎么办?
即如何(外部)定义在 class Internal
中声明的 operator<<
来自以下示例:
#include <iostream>
template <typename T>
class External {
public:
explicit External(T initial) : value{initial} {}
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
friend std::ostream& operator<<(std::ostream& os, const Internal& i);
// ^^^ this one
/* body
{
return os << i.internal_value;
}
*/
T internal_value;
};
friend std::ostream& operator<<(std::ostream& os, const External& e)
{
return os << Internal{e};
}
private:
T value;
};
int main()
{
std::cout << External<int>{5};
}
问题来了。尽管 External
是模板而 Internal
是依赖类型。 friend 函数本身不是模板化的。看起来很奇怪,它不依赖于模板参数。
当您内联定义它时,模板的每个特化也会创建关联的友元函数。但是当它不是内联时,你需要为每个特化显式提供运算符的定义。你不能用模板来做,因为函数不是模板。
因此,如果您在模板声明之后添加:
std::ostream& operator<<(std::ostream& os, External<int>::Internal const& i)
{
return os << i.internal_value;
}
它将构建。如您所见,函数中只使用了具体类型。
显然这不是一个很好的解决方案。任何明智的人都希望 External
的特化来生成朋友定义。以可维护的方式实现这一点的方法是保持运算符定义 内联 ,但不是在那里做工作,而是委托给成员函数( 是 取决于模板参数):
class Internal {
public:
Internal(const External& e) : internal_value{e.value} {}
private:
std::ostream& print(std::ostream&) const;
friend std::ostream& operator<<(std::ostream& os, Internal const& i)
{
return i.print(os); // Short and sweet on account of being inline
}
T internal_value;
};
//....
template<typename T>
std::ostream& External<T>::Internal::print(std::ostream& os) const {
// Provided outside of the class definition, can be as verbose as you like
return os << internal_value;
}