C++20有望實現自動PIMPL嗎?

*補充,似乎大家沒明白我為什麼這麼在意pimpl,在意分離。最大的原因是編譯速度,盡量少的編譯量,不想稍微改一下就要重新編譯N個模塊,這樣應該能理解吧。

為了一個分離聲明和實現血都要吐了,什麼pimpl、純虛介面、模板特化顯示實例化(勉強能分離模板)都用過了。

現在發現,其實一切的一切就是對象實例的問題,必須知道對象結構才能初始化,所以必須要用pimpl等手段才能滿足這個要求。

那麼為什麼不用上像Java那樣的手段呢,編譯器自動完成,如果不想破壞舊東西,那麼可以加一個object來作為class的正確版本:

// Fuck.h
object Fuck
{
public:
Fuck(int init);
int Header() const;
};
// http://Fuck.cc
object Fuck
{
int dropout_cxx_class_model;
public:
Fuck(int init):dropout_cxx_class_model(init){}
int Header() const
{
return dropout_cxx_class_model;
}
};
// http://Fucker.cc
#include "Fuck.h"
#include &
int main()
{
Fuck fuck(2020);
std::cout &<&< fuck.Header() &<&< endl; return 0; }

就像以上的代碼一樣,聲明只需要聲明,成員等玩意完全交給實現,完全不需要出現在頭文件。編譯器自動把Fuck給pimpl化。

這樣一來,相當於隱藏了shared_ptr/unique_ptr。只要是object聲明的都自動套上智能指針而且不需要-&>,可以做到最大限度的兼容那些舊時代包袱,不影響原本的class。

……

不知道C++的標準能不能把這類設計給列入,那些委員會和諸多c艹人士肯定早就關注這一缺陷不知道多少年了,也肯定一直在想辦法解決,但是從c艹14到c艹17都沒看到身影,我不信自動PIMPL能有多大難度,也就那樣,只可能是委員會那批人覺得不重要或者怕兼容問題。

……

真的是搞出血了,多少年了,每次都會被煩的想*$^/|*! 也就是這種時候,就很想像.java .cs那樣寫代碼,來個.c++多舒服啊。


想用Fuck而不是Fuck*或者shared_ptr&作為變數的話,你覺得計算變數佔用堆棧大小的時候,sizeof(Fuck)想返回啥?C++的其中一個要求就是,要你保證任何地方看到的class都長一樣(特別是大小)。如果不一樣的話,C++編譯器有權自己挑選一個看著順眼的,譬如說雖然你真正的class Fuck寫在了http://Fuck.cc裡面,但是鏈接的時候就是覺得http://Fucker.cc那個更好啊,然後你就buffer overflow了(逃

作為一門只能靠源碼發布庫才能使用所有能力的語言,C++隱藏實現細節是沒有意義的,反正private的東西不也不能調用嗎?如果你是想提高編譯速度的話,換個SSD。如果你是想強迫人們用指針,那構造函數也private就好了。


首先,C++現有部分是絕對不可能修改的,因為這會破壞現有代碼的內存布局。

如果加個新體系,主要的問題大概是工作量太大吧。而且新體系不可能獨立存在,它和現有類型相互使用、繼承時候的行為,想想就是個遠古巨坑。


不想稍微改一下就要重編N個模塊,出發點對了,結論錯了。

理論上所有的依賴都需要重新編譯,只是cpp處理是繼承了上個世紀的c語言而已。

而且換方式的話,標準估計得大修=》大量代碼得重寫

這裡面有些答案就是在逗比吧:「你要分離實現的話,不僅不能放在棧上,」這是什麼狗屁不同的結論。

解決編譯時間問題可以用pimpl,但是定義和實現分離和PIMPL無關。設置和定義和實現是否分離無關。你既然舉了java的例子,他實現和定義分離了?

減少編譯時間的最好辦法當然是拋棄頭文件了,趕快去給module投票!

說個自己的看法與結論,cpp 每個cpp都是一個編譯單元(每個單元都能看到所有自己需要的信息,否則就編譯錯誤了),這樣做到了編譯上的並行化。然而這對於重複的東西需要反覆的做。

其他語言java/c#的想法不是如此,他們的語法也不支持模板這種東西。但是對於一些東西,他們x確實只需要做一次,然而付出了其他的代價,並且並行化也不是很好重(但並不需要並行化)

如果每個.cpp文件編譯只需要1ms多好


如果失去了在棧上構造對象的能力,你為什麼不用其他語言。

*補充:對不起,我真不在意編譯時間,用 C++ 我第一考慮的是執行效率,業內對於 C++ 編譯時間的解決方案就是堆機器,你要分離實現的話,不僅不能放在棧上,不管什麼對象每次拷貝都要分配內存,方法也不能內聯,傳值參數的棧拷貝也不能被優化掉,為了高效必須人工區分常引右引,模板也不能用了,拋棄那麼多 C++ 的優勢,所以你為什麼不用其他默認在堆上構造對象並且有 GC 內存分配開銷少的語言呢?


假如 Herb Sutter 的 metaclass 弄出來說不定能解決這問題。

到時候可能可以利用元類自動生成轉發介面的 pImpl 包裝類,然後在 module 中 export 這些包裝類就行。

目前這種翻譯單元的模式,應該是沒人打算救的。

(這樣下來 C++ 又解決了一個 Pascal 二十多年前解決的問題……)


不是你是不是對pimpl有什麼誤解。如果說在c++11之前手寫pimpl還有注意事項的話,現在有了unique_ptr以後pimpl已經無腦了。談何吐血。也不明白為什麼pimpl還要shared_ptr,你要跟誰share你的private實現?還是你覺得自動給全世界加上shared_ptr是一種有道理的設計?

可能有點小意義的是可以搞點新特性讓unique_ptr&在不知道T是什麼類型的時候就可以知道它的大小。然後就不用狼狽地把析構函數寫在cpp文件里了(然而雖然狼狽但是也不麻煩)。

或者搞個辦法讓我可以在編譯cpp文件的時候自動生成那個析構函數也行,哪怕是生成了很多份而且是weak的也無所謂,反正很容易保證多份就是同一份,就像你寫在頭文件里的類成員函數一樣,沒損失。


題主似乎對C++有什麼誤解,C++的第一原則是運行時 zero cost,然後在不違背第一原則的情況下才會做提高開發效率,提高編譯速度等嘗試。以及實現 PIMPL 的語言有很多選擇,而能做到運行時 zero cost 的高級語言只有 C++ (最多就是加上 rust),對於題主這種嫌開發效率低,而運行時效率沒那麼重要的,應該選擇換一個語言,而不是讓 C++ 變得跟其他語言一樣。。

而且 C++ 的歷史包袱這麼重,語法那麼複雜,那麼難學難用,要是按題主說的實現,連最根本的 zero cost 都丟了,新項目誰還會用它(逃


工業上,能用錢解決的問題都不大。

編譯速度慢?多加機器並行編譯就ok了。

別讓貧窮限制了你的想像力……光速逃)


這和zero-overhead abstraction不吻合


題主這麼喜歡Fuck來、Fucker去的,要不我給Clang的詞法分析Token添上這個KEYWORD吧?!llvm-mirror/clang Code Review的時候標題都想好了 [Lex] FUCK KEYWORD ? xiangzhai 不逃,在工具鏈那兒等您 :)


這個不用加新特性也用著方便了,只要替換不用構造函數。題主用的是組合方式實現,其實用繼承寫法就很簡潔了。如不滿意,再定義幾個helper macro就行。

class Foo {

public:

virtual ~Foo() {};

static shared_ptr& create();

}

class FooImpl : public Foo {

}

shared_ptr& Foo::create() {

return make_shared&();

}


Java能這麼搞得原因是因為編譯器分析了.class文件找到了完整的定義,C艹不能這樣玩吧?


除了保證二進位兼容外,其他看不出有多大意義。

*我也不在意編譯時間,而且,有的是辦法提高編譯速度。


恰恰相反,手寫pimpl才是正途。否則你會失去在棧上構建對象的能力。


首先,個人認為這不是缺陷,如果你真想這樣,可以自己寫個generator之類的,或者換個語言

其次,header file和source file本來就算聲明和實例分離。如果真要pimp這樣,詳情可參考Qt源碼

最後,希望提問題能注意一下措辭,不要帶過多的情緒化詞語


所以為什麼不直接用C#呢?


推薦閱讀:

如何評價c++的協程庫libgo?
為什麼一般要用#include「xxx.h」?
模塊相比於 #include 指令的優點是什麼?

TAG:編程語言 | 面向對象編程 | C |