[闲聊] 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