簡體   English   中英

在模板類中聲明與朋友相同的模板類?

[英]Declare same template class as friend inside the template class?

考慮以下:

template<std::integral T>
class Integer {
  T value;

  template<std::integral T2>
  friend class Integer;

 public:
  template<std::integral T2>
  friend bool operator==(Integer<T> x, Integer<T2> y) {
    return x.value == y.value;
  }
};

Integer類定義了友元operator==來比較其他具有不同模板參數的實體,並將模板Integer類聲明為友元類。

但是當我比較兩個具有不同模板參數的對象時:

Integer<int> x;
Integer<long> y;
x == y;

Clang 接受它,但 GCC 和 MSVC 拒絕它

<source>:11:25: error: 'long int Integer<long int>::value' is private within this context
   11 |     return x.value == y.value;
      |                       ~~^~~~~

這讓我有點吃驚。 在我看來,它應該是格式良好的,因為operator==Integer<int>的朋友,而Integer<long>Integer<int>的朋友,所以operator==也應該有訪問成員的權限的Integer<long>

那么我應該信任哪個編譯器?

更新

這是CWG1699

[班級.朋友]

10友誼既不是繼承的,也不是傳遞的。 [示例 8:

 class A { friend class B; int a; }; class B { friend class C; }; class C { void f(A* p) { p->a++; // error: C is not a friend of A despite being a friend of a friend } }; class D : public B { void f(A* p) { p->a++; // error: D is not a friend of A despite being derived from a friend } };

— 結束示例]

實例化Integer<int> “注入”以下函數:

template<std::integral T2>
  friend bool operator==(Integer<int> x, Integer<T2> y)

現在,雖然Integer<int>可能是Integer<long>的朋友,但添加的operator==不是 它最多只是Integer<int>的朋友。 所以它不能訪問Integer<long>的私有成員。 當然,同樣的分析也適用於另一個方向(這並不重要,因為重寫的候選人被認為是較差的匹配1 )。

如果你想要混合比較,你需要對稱。 兩個參數都必須是未知的Integer (具有自己的模板參數),並且類模板需要與運算符成為朋友。

不幸的是,這也意味着操作符不能被內聯定義(因為每個實例化都會“注入”並重新定義它)。 所以這是可行的解決方案:

template<std::integral T>
class Integer {
  T value{};

 public:
    template<std::integral T2, std::integral T3>
    friend bool operator==(Integer<T2> x, Integer<T3> y);
};

template<std::integral T2, std::integral T3>
bool operator==(Integer<T2> x, Integer<T3> y) {
    return x.value == y.value;
}

1 over.match.best.general/2.8 - "...一個可行的函數 F1 被定義為比另一個可行的函數 F2 更好的函數,如果 ... F2 是一個重寫的候選者 ([over.match.oper]) 並且F1不是”

你朋友的朋友不是你的朋友。

#include <concepts>

template<std::integral T>
class Integer {
  T value;

  template<std::integral T2>
  friend class Integer;

 public:
  template<std::integral T2>
  bool operator==(Integer<T2> y) const {
    return value == y.value;
  }
};

int main() {
  Integer<int> x;
  Integer<long> y;
  return x == y;
}

這是有效的,因為成員operator==已成為朋友。

另一種方法是使用私有子類訪問器“key”對象:

struct GetValue {
  template<std::integral T2>
  T operator()(Integer<T2> const& self)const{
    return self.value;
  }
};

作為成員類,它確實可以訪問其包含類的友誼。

一旦我們有了這個,那么operator==簡單並且可以保持一個免費的友元函數:

template<std::integral T2>
friend bool operator==(Integer<T> x, Integer<T2> y) {
  return GetValue{}(x) == GetValue{}(y);
}

使operator==具有的GetValue “鍵”對象的能力提供了通過GetValue對象讀取不同Integer<T2>的值的能力。

這不是一個很好的答案; @storyteller 在那里做得很好。 這僅僅是解決問題的兩種清潔技術。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM