c – 如何在模板类的嵌套类中提供友元运算符的定义?

前端之家收集整理的这篇文章主要介绍了c – 如何在模板类的嵌套类中提供友元运算符的定义?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这有效:
  1. template<class Tim>
  2. struct Bob
  3. {
  4. struct Dave
  5. {
  6. Tim t{};
  7. friend bool operator < (const Dave& a,const Dave& b)
  8. {
  9. return a.t < b.t;
  10. }
  11. } d;
  12. };

这不起作用:

  1. template<class Tim>
  2. struct Bob
  3. {
  4. struct Dave
  5. {
  6. Tim t{};
  7. friend bool operator < (const Dave& a,const Dave& b);
  8. } d;
  9. };
  10.  
  11. template<class Tim>
  12. bool operator < (const typename Bob<Tim>::Dave& a,const typename Bob<Tim>::Dave& b)
  13. {
  14. return a.t < b.t;
  15. }

例如,当我尝试在地图中使用它时,我会收到链接错误

  1. 1>ConsoleApplication1.obj : error LNK2019: unresolved external symbol "bool __cdecl operator<(struct Bob<int>::Dave const &,struct Bob<int>::Dave const &)" (??M@YA_NABUDave@?$Bob@H@@0@Z) referenced in function "public: bool __thiscall std::less<struct Bob<int>::Dave>::operator()(struct Bob<int>::Dave const &,struct Bob<int>::Dave const &)const " (??R?$less@UDave@?$Bob@H@@@std@@QBE_NABUDave@?$Bob@H@@0@Z)

.

  1. int main()
  2. {
  3. std::map<Bob<int>::Dave,int> v;
  4. v[{}];
  5. }

如何在课外正确定义此运算符?

解决方法

你通常会通过向前声明模板类和友元函数然后在类定义中提供特化来做这样的事情.但是,在这种情况下,它并不那么容易 – 具有依赖类型将Tim类放在非推导的上下文中,因此推论将失败.但是,有一种解决方法
  1. #include <iostream>
  2. #include <type_traits>
  3. #include <map>
  4.  
  5. template<class T>
  6. struct Bob;
  7.  
  8. template<typename T,typename>
  9. bool operator < (const T& a,const T& b);
  10.  
  11. struct DaveTag {};
  12.  
  13. template<class Tim>
  14. struct Bob
  15. {
  16. struct Dave : DaveTag
  17. {
  18. Tim t{};
  19.  
  20.  
  21. friend bool operator < <Bob<Tim>::Dave,void>(const typename Bob<Tim>::Dave& a,const typename Bob<Tim>::Dave& b);
  22. } d;
  23. };
  24.  
  25. template<typename T,typename = typename std::enable_if<std::is_base_of<DaveTag,T>::value>::type>
  26. bool operator < (const T& a,const T& b)
  27. {
  28. return a.t < b.t;
  29. }
  30.  
  31. struct X {
  32. double t;
  33. };
  34.  
  35. int main()
  36. {
  37. std::map<Bob<int>::Dave,int> v;
  38. v[{}];
  39.  
  40. // This won't work
  41. // X x,y;
  42. //bool b = x < y;
  43.  
  44. }

基本上,我在这里所做的是让编译器推导出完整的Bob< Tim> :: Dave作为运算符<的模板参数.然而,显然一个简单的定义将允许推断出任何类型的T可能导致一些难以理解的问题.为了避免它,我添加了一个小标签类DaveTag,它允许阻止我们非常通用的运算符的实例化<除了戴夫之外什么都没有.

猜你在找的C&C++相关文章