home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 31,829 of 33,346   
   =?ISO-8859-15?Q?Daniel_Kr=FCgler?= to All   
   Re: boost::format vs. in-class 'static c   
   22 Jan 12 19:10:23   
   
   From: daniel.kruegler@googlemail.com   
      
   Am 22.01.2012 09:50, schrieb Jonathan Thornburg:   
   > I recently ran across an interesting problem in combining two parts of   
   > C++ that individually work beautifully:  boost::format  and in-class   
   > 'static const int' constants.   
   >   
   > The following toy code illustrates the problem:   
   >   
   >     #include   
   >     #include "boost/format.hpp"   
   >   
   >     using std::cout;   
   >     using boost::format;   
   >   
   >     // identity function   
   >     inline int I(int x) { return x; }   
   >   
   >     // declaration of class containing in-class 'static const int'   
   >     class   foo   
   >             {   
   >     public:   
   >             static const int N = 42;   
   >             };   
   >   
   >     int main()   
   >     {   
   >     cout<<  "raw output:   N  = "<<    foo::N<<  "\n";   
   >     cout<<  "raw output: I(N) = "<<  I(foo::N)<<  "\n";   
   >     #if 0   
   >     cout<<  format("boost::format output:   N  = %d\n") %   foo::N;   
   >     #endif   
   >     cout<<  format("boost::format output: I(N) = %d\n") % I(foo::N);   
   >   
   >     return 0;   
   >     }   
   >   
   > Here we've declared a class  foo  containing an in-class constant int   
   >   foo::N .  So long as we don't try to take the address of  foo::N   
   > (i.e., so long as we don't try to form a pointer or reference to it)   
   > everything is fine, and in particular we don't need to explicitly   
   > define  foo::N  outside the class declaration.   
      
   Correct. More precisely, the criterion for a required definition (as of   
   C++11) is whether the object is odr-used.   
      
   > In particular, there's no problem in printing  foo::N  by sending it to   
   >   std::cout , or in passing  foo::N  by value to a function  I() .  And   
   > there's no problem in using  boost::format  to print  I(foo::N) .   
   > However, if we change the "#if 0" to "#if 1", and thus try to print   
   >   foo::N  using  boost::format , then the program fails to link   
   [..]   
   > because  boost::format  takes its arguments by reference-to-const, so   
   > we're now asking the compiler to form a reference to  foo::N , which   
   > has never been explicity defined.   
      
   Right.   
      
   [..]   
   > So, what to do if we want to use boost::format to print out (messages   
   > which include) in-class constant ints?  I can see several possible   
   > solutions:   
   >   
   > We could explicitly define the in-class constant ints outside the class   
   > declaration.  This is awkward on two grounds:   
   > * it makes the code less readable: N must then be initialized in the   
   >    definition,   
      
   This is wrong, providing the definition separately does not require to   
   move the initializer to the point of the definition. According to   
   [class.static.data] p3:   
      
   "[..] The member shall still be defined in a namespace scope if it is   
   odr-used (3.2) in the program and the namespace scope definition shall   
   not contain an initializer."   
      
   > which lives in a .cc file far away (in the source code)   
   >    from the .hh file where the class is declared, so reading the .hh file   
   >    no longer tells the programmer a key piece of information about N   
   >    (its value).   
   > * if the class is actually a template, the definition needs to be   
   >    replicated for each instantiation of the template   
      
   I don't know what you mean with "replicated", and I don't see a problem   
   here for you. It is the compiler who has to ignore the multiple   
   instantiations, not you.   
      
   > We could use an enum instead of 'static const int', so as to get a truly   
   > compile-time constant.  Alas, boost::format  (at least in the version I'm   
   > using) doesn't know how to output an enum, so code trying to do so fails   
   > to compile:   
   >> boost-format-call-by-ref2.cc:26: error: no match for 'operator%' in   
   'boost::basic_format, std::allocator    
   >(((const char*)"boost::format output:   M  = %d\012")) % M'   
   >   
   > We could use an explicit identity function  I()  which takes its argument   
   > by *value*, and (as in the above code) apply  I()  to the in-class constant   
   > int before printing.   
   >   
   > At the moment my preferred solution is the last of these, with an explicit   
   > identity function.  Are there other (more-elegant) solutions?  Are there   
   > other cogent arguments for/against various solutions?   
      
   I don't see any reason for enums or explicit identity functions, just   
   provide a definition without initializer and you are done. The single   
   ugliness of this solution is that you have to provide the definition in   
   a separate file.   
      
   HTH & Greetings from Bremen,   
      
   Daniel Krügler   
      
      
   --   
         [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
         [ comp.lang.c++.moderated.    First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca