2013-05-14 25 views
3
struct X 
{ 
    void f(double) {} 
    static void f(int) {} 
}; 

int main() 
{ 
    X x; 

    auto y = x.f; 
} 

GCC給出:在類成員訪問中沒有參數列表的重載解析?

error: unable to deduce ‘auto’ from ‘x.X::f’ 

x.f類成員訪問postfix-expression在5.2.5記錄[expr.ref]

它有效地說道:

如果f是一個(可能是重載的)成員函數,函數重載決議(13.3)用於確定 - 是否x.f引用靜態或非靜態成員函數。 (來自N3485 5.2.5.4.3)

如何在這裏應用重載分辨率 - x.f沒有重載分辨率的參數列表?

或者我錯過了什麼?

更新:如果我改變auto y = x.f線到expression-statement

- auto y = x.f; 
+ x.f; 

然後gcc的,而不是抱怨:

error: statement cannot resolve address of overloaded function 
+0

是的,發現在發佈評論之後, y – 2013-05-14 11:38:13

+0

IMO您可以將此問題發送給委員會/郵件列表; [expr.ref] 4 /至少是不精確的,可以說它甚至是錯誤的(*重載解析* vs [over.over])。 – dyp 2013-05-14 13:16:56

回答

3

我認爲你是正確的,標準是不是在這一點上精確:

[expr.ref/4

如果f是一個(可能過載)成員函數,函數重載解析(13.3)被用於確定是否x.f是指一個靜態或非STA tic成員函數。

作爲第一子子彈狀態:

如果是指靜態成員函數和E2的類型是「參數類型列表返回的T功能」,然後E1.E2是一個左值;表達式指定靜態成員函數。 E1.E2的類型與E2的類型相同,即「返回T的參數類型列表的功能」。

即,x.f可用於初始化功能的ptr如果f是靜態的,而(見下面的子子彈)如果f不是靜態的,它只能在一個函數調用表達式中。

但實際上,過載分辨率不進行來選擇功能的呼叫表達的上下文之外從過載功能的名稱的過載:

[over.over]/1

重載函數名稱不帶參數的使用在特定上下文中解析爲函數,指向函數的指針或指向過載集中特定函數的成員函數的指針。 [...] 所選功能是其類型與上下文中所需目標類型的功能類型相同的功能。

即完全匹配,不調用[over.match]中描述的重載解析機制。因此[expr.ref]/4是不完整的,不會描述使用x.f初始化函數指針/引用的情況。

由於auto關鍵字未指定目標類型(或根據[dcl.spec。自動/ 6,該機構以推斷爲auto類型失敗),則不能使用auto y = x.f;

  • x.f是指一組重載函數
  • 需要選擇從該集合的函數
  • 選擇基於重載分辨率(在函數調用表達式中,此處不適用)或基於目標類型
  • 這裏沒有目標類型,或者說,目標類型等同於模板參數,因此類型推導對於auto失敗

類型的x.f因此是

    在函數調用的上下文
  • ,直接引用[expr.ref/4
  • 否則,它是一組重載函數,然後根據[over.over]選擇功能,然後根據[expr.ref]/4確定類型
2

即使有在這種情況下,只有一個x.f有效,編譯器必須在確定函數是否爲靜態之前先執行重載分辨率。

§5.2.5«如果E2是一個(可能過載)成員函數,函數重載 分辨率(13.3)被用於確定是否E1.E2指的是 靜態或非靜態成員功能。 »

的重載解析機制(如在§13.3描述和§13.4)需要一個有效的上下文來選擇正確的候選:

§13.4.1«甲使用重載函數的不帶參數的名稱在某些情況下被解析爲一個函數,函數指針或 指針成員函數用於從所述過載 組的特定功能»

auto y = x.f;不是有效的解決情況下,你要麼不得不放棄了auto關鍵字或使用static_cast迫使重載決議:

X x; 

auto y = static_cast<void (&)(int)>(x.f); 
y(1); 

auto z = static_cast<void (X::*)(double)>(&X::f); 
(x.*z)(1.); 

請注意,你不能有一個非靜態成員的引用,只有一個指針,按照§8.3。3

沒有「引用給成員」型的C++

+0

是的,但上述表達式'x.f'的類型和值類別是什麼,標準中記載了哪裏?看起來標準需要在'x.f'上重載解析,然後才能記錄'x.f'究竟是什麼?除非我錯過了某些東西 – 2013-05-14 12:01:21

+0

這隻適用於靜態功能。但是對於成員函數呢?靜態投射是UB。 – 2013-05-14 12:06:28

+0

在確定'x.f'是否爲靜態之前,編譯器需要執行重載解析**。它不能對函數簽名沒有任何限制的情況下進行重載解析。如果你不給參數類型約束,那麼你必須進行強制轉換來約束函數簽名。 – zakinster 2013-05-14 12:06:38