
{"id":2618,"date":"2018-12-12T23:03:36","date_gmt":"2018-12-13T04:03:36","guid":{"rendered":"https:\/\/ikriv.com\/blog\/?p=2618"},"modified":"2018-12-12T23:10:41","modified_gmt":"2018-12-13T04:10:41","slug":"forth-to-the-past-c-features-i-forgot-i-hate","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=2618","title":{"rendered":"Forth to the past: C++ &#8220;features&#8221; that make life hard"},"content":{"rendered":"<p>This is a continuation of the C++ series, <a href=\"https:\/\/ikriv.com\/blog\/?p=2612\">previous post here<\/a>. When I was working on the <a href=\"https:\/\/github.com\/ikriv\/cpp-move-semantics\">move semantics example<\/a>, I ran into two familiar, yet forgotten &#8220;features&#8221; of C++ that caused me major pain:<\/p>\n<ul>\n<li>Template code is not verified for correctness unless instantiated.<\/li>\n<li>Any single-parameter constructor creates an implicit conversion.<\/li>\n<\/ul>\n<p>These annoyances are not created equal: the former is much, much more painful than the latter. Modern C++ is all about templates, but you can write any old nonsense in a template: as long as it can pass the lexer, the template will compile. The real correctness check happens when (and if) the tempalte is instantiated, and in C++ it is often hard to tell when it happens and whether it happens at all, especially if we are talking about a nameless method like a constructor or an assignment operator. In practice this means that it is entirely possible to write a method with a typo, have a program compile and even run, and then discover the error days, weeks, or even months later.<\/p>\n<p>For instance, if I go to matrix.h in my example and replace assignment operator of the <code>matrix<\/code> class with the following &#8220;code&#8221;<\/p>\n<pre>matrix&amp; operator=(matrix const&amp; other)\r\n{\r\n  &lt;div style=\"color:red;font-size:15px\"&gt;\r\n    FREE PIZZA FOR ALL!!!\r\n  &lt;\/div&gt;\r\n}<\/pre>\n<p>the program still happily compiles. Assignment operator for matrices is not instantiated. Some rudimental checks are done, e.g.\u00a0<code>&amp;nsbp;<\/code> compiles, but <code>@override<\/code> does not: &#8216;@&#8217; is an illegal character. I am not sure what are the rules exactly (<a href=\"https:\/\/ikriv.com\/blog\/?p=2612\">the C++ standard costs top dollar<\/a>), but anyway, the problem is not limited to typos: you can write code that could not be valid C++ under any circumstances, and it will compile.<\/p>\n<p>Implicit conversions are less frequent, but sometimes more baffling. I have class <code>logger<\/code> with a constructor along these lines:<\/p>\n<pre>class logger\r\n{\r\npublic:\r\n    logger(std::ostream&amp; stream) : n_indent(0), m_stream(stream) {}\r\n    ...\r\n}<\/pre>\n<p>I then have two operators:<\/p>\n<pre>std::ostream&amp; operator&lt;&lt;(std::ostream&amp; stream, logger const&amp; logger);\r\ntemplate&lt;typename T&gt; std::ostream&amp; operator&lt;&lt;(logger const&amp; logger, T&amp;&amp; value);\r\n<\/pre>\n<p>If I write something like<\/p>\n<pre>logger x(cout); \r\ncout &lt;&lt; x;<\/pre>\n<p>I get a compilation error: two operators above are in conflict. The first one is applicable, but involves an implicit conversion of the right operand from <code>logger<\/code> to <code>logger const&amp;<\/code>, and the second one is applicable, but involves an implicit conversion of the left operand from <code>ostream<\/code> to <code>logger<\/code>. C++ cannot choose between the two, and thus complains.<\/p>\n<p>When I defined a constructor for <code>logger<\/code>, the last thing I thought of was implicit conversions. When I&#8217;ve got an ambiguity error, it took me a few moments to realize what is going on, and then I said &#8216;aha!&#8217; and made the constructor <code>explicit<\/code>. Problem solved.<\/p>\n<p>BUT: turning any single-parameter constructor into an implicit conversion by default was a poor language design choice. I am sure if C++ were reworked from scracth, it would have left conversions explicit by default and would have had keyword <code>implicit<\/code> to override that. But C++ is not being reworked from scratch, and thus we get those potential land mines every time we absent-mindedly define a single-parameter constructor and forget to mark it <code>explicit<\/code>. Not cool.<\/p>\n<p>To conclude: I am not talking here about some abstract impurities that may make one&#8217;s life difficult in theory. These two actually did make my life difficult in the course of a few hours that took me to create the example.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a continuation of the C++ series, previous post here. When I was working on the move semantics example, I ran into two familiar, yet forgotten &#8220;features&#8221; of C++ <a href=\"https:\/\/ikriv.com\/blog\/?p=2618\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[7],"tags":[],"class_list":["entry","author-ikriv","post-2618","post","type-post","status-publish","format-standard","category-cpp"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2618","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2618"}],"version-history":[{"count":6,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2618\/revisions"}],"predecessor-version":[{"id":2625,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2618\/revisions\/2625"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2618"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2618"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2618"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}