簡體   English   中英

指向帶有繼承的重載成員函數的指針的非類型模板參數

[英]The non-type template parameter of pointer to overloaded member functions with inheritance

背景

請考慮以下代碼:

struct A { // a class we want to hide from the client code
  int f();
  int f(char);
  int g();
};

struct B : A {}; // the interface class

// client code:
//
// It's natural to assume a member function of T should have
// a type of int (T::*)(), right?
template <typename T, int (T::*)()> struct F {};

// compiles, of course
F<A, &A::g> {};

// doesn't compile, because &B::g is not of type `int (B::*)()`, and no
// conversion is allowed here
F<B, &B::g> {};

// compiles, because &B::g is actually &A::g
//
// but this is not I want because the class hierarchy may be deep and it's
// not easy to know what A is.
F<A, &B::g> {};

片段struct<B, &B::g> {}無法編譯,因為

  1. &B::g的類型是int (A::*)() ,而不是int (B::*)() ;
  2. 雖然從int (A::*)()int (B::*)()的隱式轉換是合法且可行的,但是在執行模板參數替換指向時,C ++標准禁止(!!)任何轉換。 -member-function模板參數。 (嚴格來說,允許轉換為nullptr_t 。)

因此, F<B, &B::g>無法匹配F的確切定義,並且無法編譯。 這很難過,因為class A可能是我們不想打擾的實現細節。

解決方法

一個天真的黑客將是

template <typename T, T val> struct G {};

// at least compiles, and don't have to be aware of A
G<decltype(&B::g), &B::g> {};

到現在為止還挺好。

問題

上面的hack不適用於重載的類方法。 通常,重載可以通過static_cast來解決,但這需要我們知道&B :: f的確切類型 - 一個很好的雞蛋和雞蛋情況。

// won't compile since &B::f is ambiguous
G<decltype(&B::f), &B::f> {};

// won't compile just like F<B, &B::g>
G<decltype(static_cast<int(B::*)()>(&B::f)), &B::f> {};

// compiles, but require the knowledge of the type of &B::f
G<decltype(static_cast<int(A::*)()>(&B::f)), &B::f> {};

G<decltype(static_cast<int(A::*)()>(&B::f)), &B::f> {}; 真可怕

總結一下,問題是如何正確選擇特定的重載並避免在&B::f實際上是&A::f時提及基類A

有什么想法嗎?

我找到了符合我要求的解決方法。 希望它對有需要的人有所幫助。 我被困了幾天......

這個想法是使用函數模板來匹配特定的重載,然后將正確的類型傳遞給G 一層間接總能拯救世界。

template <typename T>
auto forward_pmf_with_signature( int(T::*pmf)() ) -> decltype(pmf);

G<decltype(forward_pmf_with_signature(&B::f)), &B::f> {}; // works

G在沒有A意識的情況下A並選擇正確的過載,很酷。

現在新的問題是我發現G<decltype(forward_pmf_with_signature(&B::f)), &B::f>是冗余的並且容易出錯。 使用宏USE_G(&B::f)來簡化代碼是微不足道的,但在我看來,以語義方式進行簡化並不容易,甚至可能。

暫無
暫無

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

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