[英]Calling pointer-to-member function in call for a function passed to a template function
[英]Call to constant pointer-to-member function not being inlined
現在,我知道內聯沒有保證,但......
鑒於以下內容:
struct Base {
virtual int f() = 0;
};
struct Derived : public Base {
virtual int f() final override {
return 42;
}
};
extern Base* b;
我們有:
int main() {
return static_cast<Derived*>(b)->f();
}
編譯為:
main:
movl $42, %eax
ret
然而...
int main() {
return (static_cast<Derived*>(b)->*(&Derived::f))();
}
編譯為:
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl b, %eax
movl (%eax), %edx
movl %eax, (%esp)
call *(%edx)
leave
ret
哪個真的很難過。
為什么沒有內聯PMF的調用? PMF是一個不變的表達!
這里的問題是,在第一種情況下,基於類型的虛擬化將間接調用轉換為直接調用。 當您添加成員指針時,不能使用基於類型的devirtualization(因為它通過前端向下傳遞到有關所調用的類型和虛方法的優化信息,在本例中並非簡單地知道)。 通過知道B
是一個類並且知道只有在構造它之后才能調用它的成員, GCC
可以能夠不斷地將實際訪問權限折疊到virutal table
。 目前它沒有做這樣的分析。
我建議填寫GCC
bugzilla的增強請求。
並不總是可以將指針內聯到函數中(除非編譯器能夠弄清楚指針實際指向的是什么,這通常很困難,因此編譯器可能會在您預期之前“放棄”)。
編輯
擴展我的答案:所有編譯器的首要任務是生成CORRECT代碼(盡管有時這也不會發生!)。 優化(例如內聯函數)是編譯器僅在“安全”時才會執行的操作。 編譯器可能不完全“理解”上面的表達式確實是一個常量表達式,因此可以回到“讓我們做安全的事情”(通過虛函數表調用,而不是內聯函數)。 指向虛擬成員函數的指針在C ++中是一個非常棘手的主題。
這確實有點煩人,但這並不奇怪。
大多數編譯器轉換通過模式匹配來工作:識別模式並應用轉換。 那么這可能不會被優化的原因是什么? 好吧,也許只是簡單地說沒有根據這種模式編寫的轉換。
這里最具體的是,問題可能是關於&Derived::f
,gcc和clang都有一個特定的表示形式用於指向虛函數的指針:它們使用指向執行虛擬分辨率的trampoline函數的指針。 因此,可能只是這個trampoline函數是一個嵌套太多,編譯器無法透視。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.