[閒聊] C++ Stateful Metaprogramming

作者: PkmX (阿貓)   2017-09-17 13:29:47
之前有人發現 C++11/14/17 標準有個漏洞,
透過 friend + template + noexcept 可以讓一個 constexpr expression 有不同的值
原理大概是這樣的:
==============================================================================
constexpr function 可以是有定義或沒定義,這會影響到 noexcept 和 SFINAE 的結果:
constexpr void f();
constexpr void g() {};
constexpr bool a = noexcept(f()); // false
constexpr bool b = noexcept(g()); // true
如果我們可以控制一個 constexpr function 有無定義,
就可以將他當作一個 bit 來使用,
這點可以用 template + friend function 給定義達成:
constexpr void flag(int); // 宣告 flag
template<typename T>
struct writer {
friend void flag(T) {}
// 當 writer<int> 被 instatinate 時,會定義 void flag(int)
};
constexpr bool a = noexcept(flag(0)); // false
writer<int> w; // instatinate `writer<int>`
constexpr bool b = noexcept(flag(0)); // true
static_assert(a != b);
int main() {
std::cout << a << ' ' << b << std::endl; // 0 1
}
http://coliru.stacked-crooked.com/a/a6cc0faeb9f215c8
有了這鬼東西以後,就可以做出 compile-time 的 counter :
static_assert(next() != next());
http://coliru.stacked-crooked.com/a/648448a3a8d03275
稍微包裝一下就可以做出 constify 的功能:
begin_mutable_region(r); // 宣告 r
auto x = r::make<int>(1);
auto v = r::make<std::vector<int>>();
x.get() = 42; // 修改 x
v.get().emplace_back(42); // 修改 v
end_mutable_region(r); // 之後不可再修改透過 r::make 製造出來的東西
x.get() = 43; // Error
v.get().clear(); // Error
std::cout << x << std::endl; // 還是可以透過 const int& 存取 x
http://coliru.stacked-crooked.com/a/3d63a2e82c173055
其原理就是透過設定 r 當作旗標,若 r 被設立時就關閉 non-const 的 overload
不過這個技巧被 C++ 委員會認為是 ill-formed:
https://wg21.cmeerw.net/cwg/issue2118
所以未來應該會修改標準禁止這鬼東西,至於具體要怎麼做現在似乎還沒有提案
參考:
Non-constant constant expressions in C++:
http://b.atch.se/posts/non-constant-constant-expressions/
How to implement a constant-expression counter in C++
http://b.atch.se/posts/constexpr-counter/
用 stateful metaprogramming 模擬 Rust 的 borrow checker:
https://medium.com/@bhuztez/db4b5e94449f
https://github.com/bhuztez/borrow
作者: steve1012 (steve)   2017-09-22 23:09:00
感覺根本沒講清楚怎麼雷啊 隨便丟個 mvp exception overloading implicit conversion 就說這語言很雷 沒寫篇文章說服大家為啥算雷 為啥沒辦法避免 我是不太信服有多雷
作者: Lordaeron (Terry)   2017-09-22 21:10:00
既然有雷不排,放新雷? 另外,沒人說慢哦,是看有多快而已而且,從沒有人說過任何面向都沒缺點,只有說排雷而已.程式寫久了,中文邏輯會變不好.CPU本身就一堆雷了.用:不然不要用啊? 或是, 哪有沒雷的語言, 這種人根本沒理性討論的空間.充分瞭解如何對付一門語言OOXX 的,叫compiler寫程式是為了解決問題,而不是要發揮語言的OOXX.你發揮得多好都好,問題沒解決,一樣是一點價值都沒有.
作者: Ommm5566 (56天團)   2017-09-22 07:22:00
universal ref是負擔? 直接可以搬rvalue的方法說慢我還真不知道哪個語言可以處理Lvalue比Rvalue快請bibo9901大大說一下 順便說一下哪個有gc和jit的語言效能贏過c++另外說C++雷的 麻煩說一下哪個語言不雷這邊有很多會各種語言的可以和你討論連特性都不懂還可以大放厥詞 真的很好笑
作者: CoNsTaR ((const *))   2017-09-17 14:23:00
XDD
作者: LPH66 (-6.2598534e+18f)   2017-09-17 15:15:00
推一個, 不過我還滿好奇這要怎麼改...
作者: jimfan (jimfan)   2017-09-17 16:48:00
可能我差勁吧,覺得C++變得複雜到不行
作者: windows2k (程式宅 <囧>)   2017-09-17 18:44:00
不只C++啊..所有程式語言都越變越複雜, 需求越來越高C#8, Java9, PHP7..幾十年前程式語言哪有版號的觀念
作者: uranusjr (←這人是超級笨蛋)   2017-09-17 18:46:00
C++ 的問題一直都是太多東西大雜燴, 不是複雜是主題太多
作者: stucode   2017-09-17 19:46:00
C++ 威力強,可是涵蓋層面廣,難以駕馭精通。
作者: Lordaeron (Terry)   2017-09-17 21:21:00
加了這一堆東西,會比較強? 哪之前的人有什麼寫不出來?不明著沒事找事.
作者: uranusjr (←這人是超級笨蛋)   2017-09-17 21:37:00
其實新東西大體上還是不錯, 是舊包袱甩不掉舊的語法實在是太多雷再不改真的要被取代了
作者: Lordaeron (Terry)   2017-09-17 23:43:00
新的語法雷有比較少?
作者: holydc (のヮの)   2017-09-17 23:58:00
組語有什麼東西寫不出來?要高階語言做什麼
作者: xam (聽說)   2017-09-18 00:26:00
我覺得難的 template 已經很複雜了,但C++11/14裡那只是基本
作者: steve1012 (steve)   2017-09-18 00:38:00
更expressive 有啥不好 你可以選擇不要用啊
作者: Ommm5566 (56天團)   2017-09-18 06:39:00
會比較強 c++11以來多了很多強力工具move semantics/auto/lambda/shared_ptr......程式碼可以選擇跑更快or比較好讀or好維護不想用這些東西就寫成c like阿 if+while+pointer+struct
作者: ronin728 (浪人)   2017-09-18 08:03:00
C++就是洪拳啊,虎形鶴形蛇形螳螂形南少林花拳全加一塊
作者: CoNsTaR ((const *))   2017-09-18 08:41:00
有這個東東可以用 我都對tmp重新燃起希望了 拜託不要修掉啦 QQ
作者: sppmg (sppmg)   2017-09-18 10:31:00
holydc +1 ,我直覺也是asm XD
作者: Lordaeron (Terry)   2017-09-18 11:46:00
鬼扯ASM,就已經不是在討論問題了。C++多了一大堆,然後有人說,你可以C like 啊哪沒問題啊,何苦搞哪麼多?一來雷沒變少,二來反而變多各家的實作又不盡一致,何不修正舊有的問題?什麼lambda, auto的,又不是沒它們就不能寫,不好寫.
作者: Caesar08 (Caesar)   2017-09-18 12:10:00
長知識囉
作者: lc85301 (pomelocandy)   2017-09-18 12:39:00
我已經看不懂這是什麼東西了(yay
作者: steve1012 (steve)   2017-09-18 12:45:00
沒 auto 要多打字的確是很不好寫啊 lolmove semantic 跟 shared pointer 也的確更好維護又不是叫每個人實作這些功能 只是拿來用還能嫌 lol愛用 c 可以用 c啊
作者: Bencrie   2017-09-18 13:14:00
更炫炮
作者: Sidney0503 (Sidney0503)   2017-09-18 13:29:00
不爽不要用 每個語言都有自己的毛和邊界問題不同語言適用範圍也不一樣你自己也說沒auto一樣可以寫程式 沒人拿槍逼你用auto事實上就是除了C++沒有語言可以做到move semanticRvalue Reference就是只有C++11才有 這種效能上的掌控 是比其他語言強的 所以追求極致效能調教不會使用C語言而是C++你不需要這麼細微的效能處理 就不要用c++所以沒有C++11 可以用asm寫出類似&&的想法提asm沒有錯啊 並不是鬼扯C語言也有undefined behavior 不少還被C++規範來C++主場戰C++ 你也是蠻幽默的
作者: Lordaeron (Terry)   2017-09-18 14:23:00
不爽當然可以不用啊,但有人提到雷了,就當然得提啊。致於你扯的效能,我就等你一篇C++11 VS C的大作了,戰吧
作者: Sidney0503 (Sidney0503)   2017-09-18 14:32:00
地表上就是除了C++沒有語言可以玩Rvalue-ref地表上就是沒有語言可以做到比C++更細微的調教戰不起來
作者: grayStone (灰色石頭)   2017-09-18 15:02:00
c++ > c
作者: Lordaeron (Terry)   2017-09-18 15:06:00
就等你的測試大作啊,戰不戰得起,不會是用嘴吧。C++ VS C, PERORMANCE COMPARE!! 等待中。
作者: bibo9901 (function(){})()   2017-09-18 15:08:00
move semantics 是特色沒錯, 但要說是"優點"可能不適合有 gc 或 jit 的語言幾乎是不需要move semantics
作者: Sidney0503 (Sidney0503)   2017-09-18 15:14:00
有GC就是慢 比如像java 但是java有一種情況可以有接近c/c++效能的狀況 就是custom Collector
作者: bibo9901 (function(){})()   2017-09-18 15:20:00
其實用 C 做分解動作也可以有move semantics同樣的效果
作者: Sidney0503 (Sidney0503)   2017-09-18 15:20:00
成立的原因也很簡單 效能可以取決於釋放空間的時機
作者: bibo9901 (function(){})()   2017-09-18 15:21:00
但c++還多了一堆負擔: rule-of-five, universal ref. 等
作者: Sidney0503 (Sidney0503)   2017-09-18 15:28:00
那是因為不同狀況下 move和copy成本不一樣所以c++11提供了選擇複製或搬移兩種手段選擇語言本來就是針對問題選需要的工具追求極致調教的3A遊戲引擎核心幾乎都是用C++刻的然後接口成python這類手稿語言方便快速開發當然快的代價就是不穩 C++本身又包山包海 自然是會有不少行為會讓compiler錯亂 現在C++的精神就是提供大量的選擇 每個選擇都會有優缺點
作者: Bencrie   2017-09-18 15:34:00
亂七八糟
作者: Sidney0503 (Sidney0503)   2017-09-18 15:34:00
樓上這個說法我還真無法反駁 XDDDDD
作者: jimfan (jimfan)   2017-09-18 15:53:00
話說回來constexpr就是為了在編譯時間預先找出陳述式的值用以減少runtime的運算,說到底還是為了讓程式跑更快,代價係語言、編譯器變複雜(我這不是廢話嗎)用心良苦 :-)
作者: Lordaeron (Terry)   2017-09-18 17:27:00
@Sidney0503,別再嘴了,只講performance就好了。越來越多雷這件事,本來就是成立的。無可否認。
作者: holydc (のヮの)   2017-09-18 20:29:00
就已經認定新語法都是雷了,人家講什麼當然看起來都像鬼扯嘴砲囉
作者: yoco (眠月)   2017-09-19 00:03:00
...C++ 又發瘋了...
作者: Lordaeron (Terry)   2017-09-19 11:50:00
舊語法就一堆雷了,要說新語法沒雷,要怎麼講?
作者: final01 (牛頓運動定律)   2017-09-19 13:43:00
坐等yo 神開戰XD
作者: holydc (のヮの)   2017-09-19 20:03:00
連舊語法都雷了哈哈哈
作者: steve1012 (steve)   2017-09-20 00:30:00
到底是什麼雷啊 雷來雷去打高空 好像幾萬個雷一樣
作者: bibo9901 (function(){})()   2017-09-20 00:34:00
most vexing parse 就可以雷到你跳起來
作者: steve1012 (steve)   2017-09-20 00:34:00
這個"本來"是不是該有點根據啊
作者: CoNsTaR ((const *))   2017-09-20 02:03:00
不是啊 自己不會寫當然要怪語法雷啊 這樣自尊心才舒服嘛
作者: bibo9901 (function(){})()   2017-09-20 08:56:00
只有語法雷? exception 雷不雷? 多載消解雷不雷?各種implicit conversion雷不雷?
作者: CoNsTaR ((const *))   2017-09-20 09:49:00
期待樓上哪天設計出一個對任何面向都沒有缺點的語言到底是你該配合、學習怎麼駕馭一門語言和發揮它的優點還是語言應該做到讓你隨便寫都不會有問題?充分瞭解如何對付一門語言的缺點、最大限度發揮它的優點不就是「程式設計師」和別人不同的地方?要不然就寫寫程式、沒事嘴砲一下我妹也會啊
作者: steve1012 (steve)   2017-09-20 10:38:00
的確是挺不雷的啊…
作者: Killercat (殺人貓™)   2017-09-20 10:54:00
MVP我前陣子才被雷到一次 orz不過MVP比較偏向是因為相容性而無法補齊的洞不過現在已經有搭另外一座橋給你就是另外其實compile time都是小雷 runtime才是大雷....
作者: shadow0326 (非議)   2017-09-20 11:33:00
我記得在板上也看過幾次被MVP雷到的問文 XD
作者: caras   2017-09-20 12:27:00
妹妹躺著也中槍 QQ
作者: CoNsTaR ((const *))   2017-09-21 06:23:00
幫妹妹QQ XDD
作者: firejox (Tangent)   2017-09-21 09:14:00
只要能減少開發維護成本都很好:D
作者: Lordaeron (Terry)   2017-09-23 09:33:00
什麼事都有辨法避免啊,不然你以為COMPILER怎麼來?
作者: Ommm5566 (56天團)   2017-09-23 14:06:00
請問樓上compiler如何寫可以不執行檢查的情況下避免使用者把pointer指到非法區間?你說什麼事都有辨法避免啊 提出來啊
作者: Sirctal (母豬母豬 夜裡哭哭)   2017-09-23 16:57:00
既然你那麼不爽 那就別用呀 何必讓自己那麼不開心對吧
作者: CoNsTaR ((const *))   2017-09-24 00:08:00
Lor 我也想知道什麼事都有辦法避免的萬能 compiler 要怎麼避免自己什麼事都能避免 哈哈哈哈哈
作者: ronin728 (浪人)   2017-10-07 11:09:00
\戰起來/ \戰起來/

Links booklink

Contact Us: admin [ a t ] ucptt.com