成本与收益

1作者: dcdropbox9 天前原帖
“没有零成本的抽象” (https://www.youtube.com/watch?v=rHIkrotSwcc) 是一场很好的 CppCon 演讲。它告诉我们要关注成本和收益。对于 C++ 核心准则中的月份抽象,我认为以下是成本和收益。你可以选择是否认为收益大于成本: ```cpp #include <iostream> // 准则 P1 是关于在代码中直接表达思想。其中一部分是使用用户定义的类型,这些类型比 int 更好地表达一个想法。 // 本文件以 P1 中的日期/月份示例为基础进行了扩展。 // 中性 1:尽管封装了无符号整数,但并没有变得更慢。 struct CalendarType { // 中性 2:用户不知道值是基于 0 还是 1。 unsigned int value; // 成本 1:用户要么必须使用 month.value,要么我们必须为所需的方法编写样板代码。 // 缓解 1:C++ 20 中比较运算符的样板代码只需几行。 bool operator==(const CalendarType &other) const = default; std::strong_ordering operator<=>(const CalendarType &other) const = default; }; // 成本 2:我们需要编写一些样板代码。 // 缓解 2:我们已将公共代码放入基类中。 struct Year : CalendarType { explicit Year(int year) : CalendarType(year) {} }; struct Month : public CalendarType { explicit Month(int month) : CalendarType(month) {} }; struct Day : public CalendarType { explicit Day(int day) : CalendarType(day) {} }; class Date { public: Date(Year year, Month month, Day day) : m_year(year), m_month(month), m_day(day) { } Year year() const { return m_year; } Month month() const { return m_month; } Day day() const { return m_day; } private: // 成本 3:要完全理解,读者需要查看 Year、Month 和 Day 的实现。 Year m_year; Month m_month; Day m_day; }; int main() { // 成本 2: Date date1 {Year(1970), Month(4), Day(7)}; // 收益 1:读者清楚每个参数是什么。 Date date2 {Year(1983), Month(1), Day(12)}; // Date date3 {7, 4, 1979}; // 收益 2:代码编写者无法将它们放错顺序 // (由于显式声明,这段代码不会编译)。 // (是的,我略过了闰年的边界情况) bool earlierInTheYear = date2.month() < date1.month() || (date2.month() == date1.month() && date2.day() < date1.day()); std::cout << "1983-01-12 " << (earlierInTheYear ? "is" : "is not") << " earlier in the year than 1970-04-07" << std::endl; } ```
查看原文
&quot;There are no zero-cost abstractions&quot; (https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=rHIkrotSwcc) is a good CppCon talk. It tells as to look for costs and benefits. For the C++ Core Guideline&#x27;s Month abstraction here are what I see as the costs and benefits. Your choice whether you feel the benefits outweigh the costs :<p>#include &lt;iostream&gt;<p>&#x2F;&#x2F; Guideline P1 is about expressing ideas directly in code. One part of that is &#x2F;&#x2F; about using user defined types that express an idea better than say an int. &#x2F;&#x2F; This file takes the Date&#x2F;Month example in P1 and expands upon it.<p>&#x2F;&#x2F; Neutral 1 : Despite wrapping the unsigned int it is no slower.<p>struct CalendarType { &#x2F;&#x2F; Neutral 2 : The user does not know if the value is 0 based or 1 based.<p><pre><code> unsigned int value; &#x2F;&#x2F; Cost 1 : Either the user has to use say month.value or we have to write boiler plate code for required methods. &#x2F;&#x2F; Mitigation 1 : C++ 20 boiler plate for comparison operators is a couple of one liners. bool operator==(const CalendarType &amp;other) const = default; std::strong_ordering operator&lt;=&gt;(const CalendarType &amp;other) const = default;</code></pre> };<p>&#x2F;&#x2F; Cost 2 : We have a bit of boiler plate code to write. &#x2F;&#x2F; Mitigation 2 : We&#x27;ve put the common code into a base class.<p>struct Year : CalendarType { explicit Year(int year) : CalendarType(year) {} };<p>struct Month : public CalendarType { explicit Month(int month) : CalendarType(month) {} };<p>struct Day : public CalendarType { explicit Day(int day) : CalendarType(day) {} };<p>class Date { public: Date(Year year, Month month, Day day) : m_year(year), m_month(month), m_day(day) { }<p><pre><code> Year year() const { return m_year; } Month month() const { return m_month; } Day day() const { return m_day; } </code></pre> private: &#x2F;&#x2F; Cost 3 : To fully understand, the reader needs to look at how Year, Month and Day are implemented.<p><pre><code> Year m_year; Month m_month; Day m_day;</code></pre> };<p>int main() { &#x2F;&#x2F; Cost 2 :<p><pre><code> Date date1 {Year(1970), Month(4), Day(7)}; &#x2F;&#x2F; Benefit 1 : It&#x27;s clear to the reader what each argument is. Date date2 {Year(1983), Month(1), Day(12)}; &#x2F;&#x2F; Date date3 {7, 4, 1979}; &#x2F;&#x2F; Benefit 2 : Code writer can&#x27;t get them in the wrong order &#x2F;&#x2F; (courtesy of explicit this wont compile). &#x2F;&#x2F; (Yes, I&#x27;ve glossed over leap year edge cases) bool earlierInTheYear = date2.month() &lt; date1.month() || date2.month() == date1.month() &amp;&amp; date2.day() &lt; date1.day(); std::cout &lt;&lt; &quot;1983-01-12 &quot; &lt;&lt; (earlierInTheYear ? &quot;is&quot; : &quot;is not&quot;) &lt;&lt; &quot; earlier in the year than 1970-04-07&quot; &lt;&lt; std::endl; }</code></pre>