作者PkmX (阿貓)
看板C_and_CPP
標題[閒聊] C++ Stateful Metaprogramming
時間Sun Sep 17 13:29:47 2017
之前有人發現 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
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.113.193.217
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1505626198.A.ED9.html
1F:推 CoNsTaR: XDD 09/17 14:23
2F:推 LPH66: 推一個, 不過我還滿好奇這要怎麼改... 09/17 15:15
※ 編輯: PkmX (140.113.193.217), 09/17/2017 15:36:12
3F:→ jimfan: 可能我差勁吧,覺得C++變得複雜到不行 09/17 16:48
4F:→ windows2k: 不只C++啊..所有程式語言都越變越複雜, 需求越來越高 09/17 18:44
5F:→ windows2k: C#8, Java9, PHP7..幾十年前程式語言哪有版號的觀念 09/17 18:45
6F:→ uranusjr: C++ 的問題一直都是太多東西大雜燴, 不是複雜是主題太多 09/17 18:46
7F:推 stucode: C++ 威力強,可是涵蓋層面廣,難以駕馭精通。 09/17 19:46
8F:→ Lordaeron: 加了這一堆東西,會比較強? 哪之前的人有什麼寫不出來? 09/17 21:21
9F:→ Lordaeron: 不明著沒事找事. 09/17 21:21
10F:→ uranusjr: 其實新東西大體上還是不錯, 是舊包袱甩不掉 09/17 21:37
11F:→ uranusjr: 舊的語法實在是太多雷再不改真的要被取代了 09/17 21:38
12F:→ Lordaeron: 新的語法雷有比較少? 09/17 23:43
13F:推 holydc: 組語有什麼東西寫不出來?要高階語言做什麼 09/17 23:58
14F:→ xam: 我覺得難的 template 已經很複雜了,但C++11/14裡那只是基本 09/18 00:26
15F:推 steve1012: 更expressive 有啥不好 你可以選擇不要用啊 09/18 00:38
16F:→ Ommm5566: 會比較強 c++11以來多了很多強力工具 09/18 06:39
17F:→ Ommm5566: move semantics/auto/lambda/shared_ptr...... 09/18 06:41
18F:→ Ommm5566: 程式碼可以選擇跑更快or比較好讀or好維護 09/18 06:41
19F:→ Ommm5566: 不想用這些東西就寫成c like阿 if+while+pointer+struct 09/18 06:45
20F:→ ronin728: C++就是洪拳啊,虎形鶴形蛇形螳螂形南少林花拳全加一塊 09/18 08:03
21F:推 CoNsTaR: 有這個東東可以用 我都對tmp重新燃起希望了 拜託不要修 09/18 08:41
22F:→ CoNsTaR: 掉啦 QQ 09/18 08:41
23F:推 sppmg: holydc +1 ,我直覺也是asm XD 09/18 10:31
24F:→ Lordaeron: 鬼扯ASM,就已經不是在討論問題了。 09/18 11:46
25F:→ Lordaeron: C++多了一大堆,然後有人說,你可以C like 啊 09/18 11:47
26F:→ Lordaeron: 哪沒問題啊,何苦搞哪麼多?一來雷沒變少,二來反而變多 09/18 11:48
27F:→ Lordaeron: 各家的實作又不盡一致,何不修正舊有的問題? 09/18 11:49
28F:→ Lordaeron: 什麼lambda, auto的,又不是沒它們就不能寫,不好寫. 09/18 11:49
29F:推 Caesar08: 長知識囉 09/18 12:10
30F:推 lc85301: 我已經看不懂這是什麼東西了(yay 09/18 12:39
31F:推 steve1012: 沒 auto 要多打字的確是很不好寫啊 lol 09/18 12:45
32F:→ steve1012: move semantic 跟 shared pointer 也的確更好維護 09/18 12:46
33F:→ steve1012: 又不是叫每個人實作這些功能 只是拿來用還能嫌 lol 09/18 12:47
34F:→ steve1012: 愛用 c 可以用 c啊 09/18 12:47
35F:推 Bencrie: 更炫炮 09/18 13:14
36F:噓 Sidney0503: 不爽不要用 每個語言都有自己的毛和邊界問題 09/18 13:29
37F:→ Sidney0503: 不同語言適用範圍也不一樣 09/18 13:29
38F:→ Sidney0503: 你自己也說沒auto一樣可以寫程式 沒人拿槍逼你用auto 09/18 13:29
39F:→ Sidney0503: 事實上就是除了C++沒有語言可以做到move semantic 09/18 13:30
40F:→ Sidney0503: Rvalue Reference就是只有C++11才有 這種效能上的掌 09/18 13:31
41F:→ Sidney0503: 控 是比其他語言強的 所以追求極致效能調教不會使用 09/18 13:31
42F:→ Sidney0503: C語言而是C++ 09/18 13:31
43F:→ Sidney0503: 你不需要這麼細微的效能處理 就不要用c++ 09/18 13:33
44F:→ Sidney0503: 所以沒有C++11 可以用asm寫出類似&&的想法 09/18 13:34
45F:→ Sidney0503: 提asm沒有錯啊 並不是鬼扯 09/18 13:34
46F:推 Sidney0503: C語言也有undefined behavior 不少還被C++規範 09/18 13:38
47F:→ Sidney0503: 來C++主場戰C++ 你也是蠻幽默的 09/18 13:42
48F:→ Lordaeron: 不爽當然可以不用啊,但有人提到雷了,就當然得提啊。 09/18 14:23
49F:→ Lordaeron: 致於你扯的效能,我就等你一篇C++11 VS C的大作了,戰吧 09/18 14:24
50F:推 Sidney0503: 地表上就是除了C++沒有語言可以玩Rvalue-ref 09/18 14:32
51F:→ Sidney0503: 地表上就是沒有語言可以做到比C++更細微的調教 09/18 14:34
52F:→ Sidney0503: 戰不起來 09/18 14:34
53F:推 grayStone: c++ > c 09/18 15:02
54F:→ Lordaeron: 就等你的測試大作啊,戰不戰得起,不會是用嘴吧。 09/18 15:06
55F:→ Lordaeron: C++ VS C, PERORMANCE COMPARE!! 等待中。 09/18 15:08
56F:→ bibo9901: move semantics 是特色沒錯, 但要說是"優點"可能不適合 09/18 15:08
57F:→ bibo9901: 有 gc 或 jit 的語言幾乎是不需要move semantics 09/18 15:09
58F:推 Sidney0503: 有GC就是慢 比如像java 但是java有一種情況可以有 09/18 15:14
59F:→ Sidney0503: 接近c/c++效能的狀況 就是custom Collector 09/18 15:15
60F:→ bibo9901: 其實用 C 做分解動作也可以有move semantics同樣的效果 09/18 15:20
61F:→ Sidney0503: 成立的原因也很簡單 效能可以取決於釋放空間的時機 09/18 15:20
62F:→ bibo9901: 但c++還多了一堆負擔: rule-of-five, universal ref. 等 09/18 15:21
63F:推 Sidney0503: 那是因為不同狀況下 move和copy成本不一樣 09/18 15:28
64F:→ Sidney0503: 所以c++11提供了選擇複製或搬移兩種手段選擇 09/18 15:28
65F:→ Sidney0503: 語言本來就是針對問題選需要的工具 09/18 15:28
66F:→ Sidney0503: 追求極致調教的3A遊戲引擎核心幾乎都是用C++刻的 09/18 15:29
67F:→ Sidney0503: 然後接口成python這類手稿語言方便快速開發 09/18 15:30
68F:→ Sidney0503: 當然快的代價就是不穩 C++本身又包山包海 自然是 09/18 15:32
69F:→ Sidney0503: 會有不少行為會讓compiler錯亂 現在C++的精神就是 09/18 15:33
70F:→ Sidney0503: 提供大量的選擇 每個選擇都會有優缺點 09/18 15:34
71F:推 Bencrie: 亂七八糟 09/18 15:34
72F:→ Sidney0503: 樓上這個說法我還真無法反駁 XDDDDD 09/18 15:34
73F:→ jimfan: 話說回來constexpr就是為了在編譯時間預先找出陳述式的值 09/18 15:53
74F:→ jimfan: 用以減少runtime的運算,說到底還是為了讓程式跑更快,代 09/18 15:54
75F:→ jimfan: 價係語言、編譯器變複雜(我這不是廢話嗎) 09/18 15:56
76F:→ jimfan: 用心良苦 :-) 09/18 15:57
77F:→ Lordaeron: @Sidney0503,別再嘴了,只講performance就好了。 09/18 17:27
78F:→ Lordaeron: 越來越多雷這件事,本來就是成立的。無可否認。 09/18 17:28
79F:推 holydc: 就已經認定新語法都是雷了,人家講什麼當然看起來都像 09/18 20:29
80F:→ holydc: 鬼扯嘴砲囉 09/18 20:29
81F:推 yoco: ...C++ 又發瘋了... 09/19 00:03
82F:→ Lordaeron: 舊語法就一堆雷了,要說新語法沒雷,要怎麼講? 09/19 11:50
83F:→ final01: 坐等yo 神開戰XD 09/19 13:43
84F:推 holydc: 連舊語法都雷了哈哈哈 09/19 20:03
85F:推 steve1012: 到底是什麼雷啊 雷來雷去打高空 好像幾萬個雷一樣 09/20 00:30
86F:→ bibo9901: most vexing parse 就可以雷到你跳起來 09/20 00:34
87F:推 steve1012: 這個"本來"是不是該有點根據啊 09/20 00:34
88F:推 CoNsTaR: 不是啊 自己不會寫當然要怪語法雷啊 這樣自尊心才舒服嘛 09/20 02:03
89F:推 bibo9901: 只有語法雷? exception 雷不雷? 多載消解雷不雷? 09/20 08:56
90F:→ bibo9901: 各種implicit conversion雷不雷? 09/20 08:57
91F:推 CoNsTaR: 期待樓上哪天設計出一個對任何面向都沒有缺點的語言 09/20 09:49
92F:→ CoNsTaR: 到底是你該配合、學習怎麼駕馭一門語言和發揮它的優點 09/20 09:49
93F:→ CoNsTaR: 還是語言應該做到讓你隨便寫都不會有問題? 09/20 09:49
94F:→ CoNsTaR: 充分瞭解如何對付一門語言的缺點、最大限度發揮它的優點 09/20 09:49
95F:→ CoNsTaR: 不就是「程式設計師」和別人不同的地方? 09/20 09:50
96F:→ CoNsTaR: 要不然就寫寫程式、沒事嘴砲一下我妹也會啊 09/20 09:50
97F:推 steve1012: 的確是挺不雷的啊… 09/20 10:38
98F:推 Killercat: MVP我前陣子才被雷到一次 orz 09/20 10:54
99F:→ Killercat: 不過MVP比較偏向是因為相容性而無法補齊的洞 09/20 10:54
100F:→ Killercat: 不過現在已經有搭另外一座橋給你就是 09/20 10:54
101F:→ Killercat: 另外其實compile time都是小雷 runtime才是大雷.... 09/20 10:55
102F:推 shadow0326: 我記得在板上也看過幾次被MVP雷到的問文 XD 09/20 11:33
103F:→ caras: 妹妹躺著也中槍 QQ 09/20 12:27
104F:推 CoNsTaR: 幫妹妹QQ XDD 09/21 06:23
105F:推 firejox: 只要能減少開發維護成本都很好:D 09/21 09:14
106F:推 Ommm5566: universal ref是負擔? 直接可以搬rvalue的方法說慢 09/22 07:22
107F:→ Ommm5566: 我還真不知道哪個語言可以處理Lvalue比Rvalue快 09/22 07:23
108F:→ Ommm5566: 請bibo9901大大說一下 順便說一下哪個有gc和jit的語言 09/22 07:23
109F:→ Ommm5566: 效能贏過c++ 09/22 07:23
110F:→ Ommm5566: 另外說C++雷的 麻煩說一下哪個語言不雷 09/22 07:25
111F:→ Ommm5566: 這邊有很多會各種語言的可以和你討論 09/22 07:25
112F:噓 Ommm5566: 連特性都不懂還可以大放厥詞 真的很好笑 09/22 07:35
113F:→ Lordaeron: 既然有雷不排,放新雷? 另外,沒人說慢哦,是看有多快而已 09/22 21:10
114F:→ Lordaeron: 而且,從沒有人說過任何面向都沒缺點,只有說排雷而已. 09/22 21:11
115F:→ Lordaeron: 程式寫久了,中文邏輯會變不好. 09/22 21:12
116F:→ Lordaeron: CPU本身就一堆雷了. 09/22 21:14
117F:→ Lordaeron: 用:不然不要用啊? 或是, 哪有沒雷的語言, 這種人根本 09/22 21:17
118F:→ Lordaeron: 沒理性討論的空間. 09/22 21:18
119F:→ Lordaeron: 充分瞭解如何對付一門語言OOXX 的,叫compiler 09/22 21:20
120F:→ Lordaeron: 寫程式是為了解決問題,而不是要發揮語言的OOXX. 09/22 21:21
121F:→ Lordaeron: 你發揮得多好都好,問題沒解決,一樣是一點價值都沒有. 09/22 21:21
122F:推 steve1012: 感覺根本沒講清楚怎麼雷啊 隨便丟個 mvp exception ove 09/22 23:09
123F:→ steve1012: rloading implicit conversion 就說這語言很雷 沒寫篇 09/22 23:09
124F:→ steve1012: 文章說服大家為啥算雷 為啥沒辦法避免 我是不太信服有 09/22 23:09
125F:→ steve1012: 多雷 09/22 23:09
126F:→ Lordaeron: 什麼事都有辨法避免啊,不然你以為COMPILER怎麼來? 09/23 09:33
127F:噓 Ommm5566: 請問樓上compiler如何寫可以不執行檢查的情況下避免使 09/23 14:06
128F:→ Ommm5566: 用者把pointer指到非法區間? 09/23 14:06
129F:→ Ommm5566: 你說什麼事都有辨法避免啊 提出來啊 09/23 14:07
130F:推 Sirctal: 既然你那麼不爽 那就別用呀 何必讓自己那麼不開心 09/23 16:57
131F:→ Sirctal: 對吧 09/23 16:57
132F:→ CoNsTaR: Lor 我也想知道什麼事都有辦法避免的萬能 compiler 要怎 09/24 00:08
133F:→ CoNsTaR: 麼避免自己什麼事都能避免 哈哈哈哈哈 09/24 00:08
134F:→ ronin728: \戰起來/ \戰起來/ 10/07 11:09