{"id":170,"date":"2010-12-23T10:02:52","date_gmt":"2010-12-23T17:02:52","guid":{"rendered":"http:\/\/blog.mezeske.com\/?p=170"},"modified":"2010-12-23T10:02:52","modified_gmt":"2010-12-23T17:02:52","slug":"c-streams-typedefs-be-charful","status":"publish","type":"post","link":"http:\/\/blog.mezeske.com\/?p=170","title":{"rendered":"C++ Streams <span class=\"amp\">&amp;<\/span> Typedefs: Be Charful"},"content":{"rendered":"<p>The C++ type\u00addef key\u00adword is indis\u00adpens\u00adable in many sit\u00adu\u00ada\u00adtions, espe\u00adcial\u00adly for writ\u00ading portable low-lev\u00adel code.  However, in some cir\u00adcum\u00adstances it can cause trou\u00adble, par\u00adtic\u00adu\u00adlar\u00adly when it comes to func\u00adtion over\u00adload\u00ading.  Consider the fol\u00adlow\u00ading C++ tem\u00adplate&nbsp;class:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"kw2\">template<\/span> <span class=\"sy1\">&lt;<\/span><span class=\"kw2\">typename<\/span> T<span class=\"sy1\">&gt;<\/span><br>\n<span class=\"kw4\">struct<\/span> foobar<br>\n<span class=\"br0\">{<\/span><br>\n&nbsp; &nbsp; foobar<span class=\"br0\">(<\/span> <span class=\"kw4\">const<\/span> T foo <span class=\"br0\">)<\/span> <span class=\"sy4\">:<\/span> foo_<span class=\"br0\">(<\/span> foo <span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span><span class=\"br0\">}<\/span><br>\n&nbsp; &nbsp; T foo_<span class=\"sy4\">;<\/span><br>\n<span class=\"br0\">}<\/span><span class=\"sy4\">;<\/span><\/div><\/div>\n<p>One might want to write a sim\u00adple stream out\u00adput oper\u00ada\u00adtor to for\u00admat the tem\u00adplate class\u2019 mem\u00adber val\u00adues, e.g. for debug\u00adging purposes:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"kw2\">template<\/span> <span class=\"sy1\">&lt;<\/span><span class=\"kw2\">typename<\/span> T<span class=\"sy1\">&gt;<\/span><br>\nostream<span class=\"sy3\">&amp;<\/span> operator<span class=\"sy1\">&lt;&lt;<\/span><span class=\"br0\">(<\/span> ostream<span class=\"sy3\">&amp;<\/span> s, <span class=\"kw4\">const<\/span> foobar<span class=\"sy1\">&lt;<\/span>T<span class=\"sy1\">&gt;<\/span><span class=\"sy3\">&amp;<\/span> fb <span class=\"br0\">)<\/span><br>\n<span class=\"br0\">{<\/span><br>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> s <span class=\"sy1\">&lt;&lt;<\/span> <span class=\"st0\">\"foo: \"<\/span> <span class=\"sy1\">&lt;&lt;<\/span> fb.<span class=\"me1\">foo_<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"br0\">}<\/span><\/div><\/div>\n<p>This seems rea\u00adson\u00adable.  Now, let\u2019s assume that this tem\u00adplate is going to be used in a con\u00adtext where T will be one of sev\u00ader\u00adal fixed-width inte\u00adger types.  These are usu\u00adal\u00adly type\u00addefs from a head\u00ader like <a href=\"http:\/\/en.wikipedia.org\/wiki\/Stdint.h\">stdint.h<\/a> (for those that don\u2019t mind includ\u00ading a C head\u00ader) or <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_38_0\/libs\/integer\/cstdint.htm\">boost\/cstdint.hpp<\/a> (to be a C++ purist).  They are com\u00admon\u00adly named int64_t, int32_t, int16_t, and int8_t, where the X in intX_t spec\u00adi\u00adfies the num\u00adber of bits used to rep\u00adre\u00adsent the inte\u00adger.  There are also unsigned vari\u00adants, but we\u2019ll ignore those for this discussion.<\/p>\n<p>Let\u2019s now explore what hap\u00adpens when we ini\u00adtial\u00adize a foobar&lt;intX_t&gt; instance with its foo_ mem\u00adber set to a small inte\u00adger and print it to stan\u00addard out\u00adput via our cus\u00adtom stream out\u00adput operator:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"kw3\">cout<\/span> <span class=\"sy1\">&lt;&lt;<\/span> foobar<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int64_t<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> <span class=\"nu0\">42<\/span> <span class=\"br0\">)<\/span> <span class=\"sy1\">&lt;&lt;<\/span> endl<span class=\"sy4\">;<\/span><br>\n<span class=\"kw3\">cout<\/span> <span class=\"sy1\">&lt;&lt;<\/span> foobar<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int32_t<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> <span class=\"nu0\">42<\/span> <span class=\"br0\">)<\/span> <span class=\"sy1\">&lt;&lt;<\/span> endl<span class=\"sy4\">;<\/span><br>\n<span class=\"kw3\">cout<\/span> <span class=\"sy1\">&lt;&lt;<\/span> foobar<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int16_t<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> <span class=\"nu0\">42<\/span> <span class=\"br0\">)<\/span> <span class=\"sy1\">&lt;&lt;<\/span> endl<span class=\"sy4\">;<\/span><\/div><\/div>\n<p>Each of these state\u00adments prints \u201cfoo: 42\u201d, as expect\u00aded.  Great, every\u00adthing works!  But wait, there was one type that we did\u00adn\u2019t&nbsp;test:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"kw3\">cout<\/span> <span class=\"sy1\">&lt;&lt;<\/span> foobar<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int8_t<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> <span class=\"nu0\">42<\/span> <span class=\"br0\">)<\/span> <span class=\"sy1\">&lt;&lt;<\/span> endl<span class=\"sy4\">;<\/span><\/div><\/div>\n<p>This prints \u201cfoo: *\u201d instead of \u201cfoo: 42\u201d.  This is prob\u00ada\u00adbly not the expect\u00aded result of print\u00ading the val\u00adue of an int8_t.  After all, it looks and feels just like all of the oth\u00ader intX_t types!  What caus\u00ades it to be print\u00aded dif\u00adfer\u00adent\u00adly from the oth\u00ader types?  Let\u2019s look at how the inte\u00adger types might be defined for an x86 machine:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"kw4\">typedef<\/span> <span class=\"kw4\">long<\/span> <span class=\"kw4\">int<\/span> <span class=\"kw4\">int64_t<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"kw4\">typedef<\/span> <span class=\"kw4\">int<\/span> <span class=\"kw4\">int32_t<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"kw4\">typedef<\/span> <span class=\"kw4\">short<\/span> <span class=\"kw4\">int16_t<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"kw4\">typedef<\/span> <span class=\"kw4\">char<\/span> <span class=\"kw4\">int8_t<\/span><span class=\"sy4\">;<\/span><\/div><\/div>\n<p>The prob\u00adlem is that the only way to rep\u00adre\u00adsent an inte\u00adger with exact\u00adly 8 bits (and no more) is with a char (at least on the x86 archi\u00adtec\u00adture).  While a char is an inte\u00adger, it is also a\u2026 char\u00adac\u00adter.  So, this trou\u00adble is caused by the fact that the char type is try\u00ading to be two things at&nbsp;once.<\/p>\n<p>A sim\u00adple (but incor\u00adrect) approach to work around this is to over\u00adload<sup><a href=\"#footnote_0_170\" id=\"identifier_0_170\" class=\"footnote-link footnote-identifier-link\" title=\"If you are curious as to why I suggest overloading instead of template specialization, see this article.\">1<\/a><\/sup> the stream out\u00adput oper\u00ada\u00adtor for the int8_t type, and force it to be print\u00aded as a number:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\"><span class=\"co1\">\/\/ This is incorrect:<\/span><br>\nostream<span class=\"sy3\">&amp;<\/span> operator<span class=\"sy1\">&lt;&lt;<\/span><span class=\"br0\">(<\/span> ostream<span class=\"sy3\">&amp;<\/span> s, <span class=\"kw4\">const<\/span> <span class=\"kw4\">int8_t<\/span> i <span class=\"br0\">)<\/span><br>\n<span class=\"br0\">{<\/span><br>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> s <span class=\"sy1\">&lt;&lt;<\/span> <span class=\"kw2\">static_cast<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> i <span class=\"br0\">)<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"br0\">}<\/span><\/div><\/div>\n<p>The prob\u00adlem with this approach is that the int8_t type\u00addef <strong>does not rep\u00adre\u00adsent a unique type<\/strong>.  The type\u00addef key\u00adword is named poor\u00adly; it does not intro\u00adduce new types.  Rather, it cre\u00adates alias\u00ades for exist\u00ading types.  By over\u00adload\u00ading the stream out\u00adput oper\u00ada\u00adtor for the int8_t type, the char type\u00ad\u2019s oper\u00ada\u00adtor is being over\u00adloaded as well.  Since the stan\u00addard library already defines a stream out\u00adput oper\u00ada\u00adtor for the char type, the above def\u00adi\u00adn\u00adi\u00adtion would vio\u00adlate the <a href=\"http:\/\/en.wikipedia.org\/wiki\/One_Definition_Rule\">One Definition Rule<\/a> and result in a com\u00adpil\u00ader error.  Even if it did com\u00adpile, the results of redefin\u00ading the way char\u00adac\u00adters are print\u00aded would prob\u00ada\u00adbly not be desirable.<\/p>\n<p>An alter\u00adna\u00adtive (work\u00ading) solu\u00adtion to the prob\u00adlem is to over\u00adload the out\u00adput stream oper\u00ada\u00adtor for the foobar&lt;int8_t&gt; type:<\/p>\n<div class=\"codecolorer-container cpp twitlight\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"cpp codecolorer\">ostream<span class=\"sy3\">&amp;<\/span> operator<span class=\"sy1\">&lt;&lt;<\/span><span class=\"br0\">(<\/span> ostream<span class=\"sy3\">&amp;<\/span> s, <span class=\"kw4\">const<\/span> foobar<span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int8_t<\/span><span class=\"sy1\">&gt;<\/span><span class=\"sy3\">&amp;<\/span> fb <span class=\"br0\">)<\/span><br>\n<span class=\"br0\">{<\/span><br>\n&nbsp; &nbsp; <span class=\"kw1\">return<\/span> s <span class=\"sy1\">&lt;&lt;<\/span> <span class=\"st0\">\"foo: \"<\/span> <span class=\"sy1\">&lt;&lt;<\/span> <span class=\"kw2\">static_cast<\/span><span class=\"sy1\">&lt;<\/span><span class=\"kw4\">int<\/span><span class=\"sy1\">&gt;<\/span><span class=\"br0\">(<\/span> fb.<span class=\"me1\">foo_<\/span> <span class=\"br0\">)<\/span><span class=\"sy4\">;<\/span><br>\n<span class=\"br0\">}<\/span><\/div><\/div>\n<p>This def\u00adi\u00adn\u00adi\u00adtion does not clash with any exist\u00ading over\u00adloads from the stan\u00addard library, and it effec\u00adtive\u00adly caus\u00ades the int8_t to be print\u00aded as an inte\u00adger.  The down\u00adside is that it will cause unex\u00adpect\u00aded behav\u00adior when a foobar&lt;char&gt; is print\u00aded, if the pro\u00adgram\u00admer intends char to rep\u00adre\u00adsent a char\u00adac\u00adter.  The only way to avoid this would be to define int8_t as a class instead of mak\u00ading it a type\u00addef, and pro\u00advid\u00ading a well-behaved stream out\u00adput oper\u00ada\u00adtor for that class.  The class\u2019 arith\u00admetic oper\u00ada\u00adtors could be over\u00adloaded to make it look almost exact\u00adly like a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Plain_old_data_structure\"><span class=\"caps\">POD<\/span><\/a> inte\u00adger, and it would\u00adn\u2019t nec\u00ades\u00adsar\u00adi\u00adly take up any extra mem\u00ado\u00adry.  However, this solu\u00adtion is still not ide\u00adal, because class\u00ades behave dif\u00adfer\u00adent\u00adly than <span class=\"caps\">POD<\/span> types in sub\u00adtle ways (e.g. <span class=\"caps\">POD<\/span> types are not ini\u00adtial\u00adized by default, but class\u00ades&nbsp;are).<\/p>\n<p>If there\u2019s any\u00adthing to take away from this, it\u2019s that the C++ char type is an odd beast to watch out for.  Also, the name of the type\u00addef oper\u00ada\u00adtor could use some improvement\u2026<\/p>\n<ol class=\"footnotes\"><li id=\"footnote_0_170\" class=\"footnote\">If you are curi\u00adous as to why I sug\u00adgest over\u00adload\u00ading instead of tem\u00adplate spe\u00adcial\u00adiza\u00adtion, see <a href=\"http:\/\/www.gotw.ca\/publications\/mill17.htm\">this arti\u00adcle<\/a>. [<a href=\"#identifier_0_170\" class=\"footnote-link footnote-back-link\">\u21a9<\/a>]<\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>The C++ type\u00addef key\u00adword is indis\u00adpens\u00adable in many sit\u00adu\u00ada\u00adtions, espe\u00adcial\u00adly for writ\u00ading portable low-lev\u00ad\u00adel code. However, in some cir\u00adcum\u00adstances it can cause trou\u00adble, par\u00adtic\u00adu\u00adlar\u00adly when it comes to func\u00adtion over\u00adload\u00ading. Consider the fol\u00adlow\u00ading C++ tem\u00adplate&nbsp;class: tem\u00adplate &lt;type\u00adname T&gt; struct foo\u00adbar { &nbsp; &nbsp; foo\u00adbar( con\u00adst T foo ) : foo_(&nbsp;foo&nbsp;)&nbsp;{}&nbsp;[\u2026]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wp_typography_post_enhancements_disabled":false},"categories":[3],"tags":[4,14,5,6],"_links":{"self":[{"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/posts\/170"}],"collection":[{"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=170"}],"version-history":[{"count":74,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/posts\/170\/revisions"}],"predecessor-version":[{"id":244,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=\/wp\/v2\/posts\/170\/revisions\/244"}],"wp:attachment":[{"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.mezeske.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}