From: clcppm-poster@this.is.invalid   
      
   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.   
      
   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   
    [I'm using g++ 4.2.4 on an OpenBSD 5.0 system, with   
    boost 1.42.0p7, but I think this behavior is generic   
    and should be the same for any reasonable C++ system   
    and boost version.]   
   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.   
      
    [In the actual application code where I encountered this   
    problem, there were a lot of templates around, and I at   
    first thought this was template instantiation (or more   
    accurately, non-instantiation) problem.]   
      
      
      
   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, 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   
      
   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?   
      
   --   
   -- "Jonathan Thornburg [remove -animal to reply]"    
    Dept of Astronomy & IUCSS, Indiana University, Bloomington, Indiana, USA   
    "Washing one's hands of the conflict between the powerful and the   
    powerless means to side with the powerful, not to be neutral."   
    -- quote by Freire / poster by Oxfam   
      
      
    [ 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)   
|