![](/img/trans.png)
[英]Implicitly pass the "this" OR the "type" of the calling class to a non-member template function
[英]Implementing non-member generic function for specific nested class of a class template
我有以下課程:
template<int P>
struct A {
struct B {
auto abs() const { return 1; }
};
};
具體而言, A
應該是模P的整數的有限域, B
是表示來自該有限域的元素的類。 然后我有擴展GCD算法的通用實現,它應該使用abs
函數。 問題我希望擴展的GCD算法實現在基本類型(int,long等)以及A<P>::B
。 所以我需要實現一個非成員abs
,它將調用A<P>::B::abs
。 我嘗試了三種技術,其中兩種不起作用,另一種起作用但不合適。
技術1(不起作用):使用參數依賴查找(ADL)。 定義的體內下列A
但身體外部B
:
auto abs(B const &e) { return e.abs(); }
它不起作用,因為ADL只查找名稱空間而不是類作用域。 更新 :ADL在這里不起作用,因為abs
是一個實例方法。 但是根據TC的回答,如果你把它作為朋友功能它可以正常工作,ADL找到它!
技術2(不起作用):在全局或命名空間范圍內使用約束函數模板:
template<int P>
auto abs(typename A<P>::B const &e) { return e.abs(); }
這也不起作用,因為P
處於非推導的上下文中。
技術3(有效但不令人滿意):在全局或命名空間范圍內使用無約束函數模板:
template<typename T>
auto abs(T const &e) { return e.abs(); }
這有效。 但是,它不受約束。 我想將此函數模板的實例化僅限制為A<P>
(對於事先未知的P
)和其他類模板(對於多項式環和字段擴展)。 問題是如果P
在非推導的上下文中,我不確定如何使用SFINAE。
template<int P>
struct A {
struct B {
auto abs() const { return 1; }
};
friend auto abs(B const &e) { return e.abs(); }
// ^^^^^^
};
然后讓ADL發揮其魔力。
(在B
定義它也很好。選擇取決於你。)
這將有效:
namespace impl {
template <int P>
struct B {
auto abs() const { return 1; }
};
template <int P>
auto abs(B<P>& b) {
return b.abs();
}
}
template <int P>
struct A {
using B = impl::B<P>;
friend B;
};
int main() {
A<3>::B inner;
abs(inner);
}
此解決方案使用ADL,因為abs
現在與B
在同一名稱空間中。 此外,我們避免了具有P
在非推導出上下文( P
不是一些左邊::
再次通過模板參數符號) B
。 不幸的是,現在B
不是A
的成員,所以如果你想讓它訪問A
的成員,你將不得不把它變成朋友。 之前的解決方案是由於這個答案 。 我們接下來會改進它。
或者,如果您確實希望B
成為A
的成員,那么您需要的只是公共外觀以確保正確的重定向:
namespace impl {
template <typename T>
struct facade : public T {};
template <typename T>
auto abs(facade<T>& b) { return b.abs(); }
}
template <int P>
struct A {
struct B_ {
auto abs() const { return 1; }
};
using B = impl::facade<B_ >;
};
int main() {
A<3>::B inner;
abs(inner);
}
這里的優點是這個公共外觀可以重復使用幾個類,而且它不一定是朋友。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.