Named parameter string formatting in C++

后端 未结 6 1969
甜味超标
甜味超标 2021-02-07 08:55

I\'m wondering if there is a library like Boost Format, but which supports named parameters rather than positional ones. This is a common idiom in e.g. Python, where you have a

6条回答
  •  甜味超标
    2021-02-07 09:54

    I've always been critic with C++ I/O (especially formatting) because in my opinion is a step backward in respect to C. Formats needs to be dynamic, and makes perfect sense for example to load them from an external resource as a file or a parameter.

    I've never tried before however to actually implement an alternative and your question made me making an attempt investing some weekend hours on this idea.

    Sure the problem was more complex than I thought (for example just the integer formatting routine is 200+ lines), but I think that this approach (dynamic format strings) is more usable.

    You can download my experiment from this link (it's just a .h file) and a test program from this link (test is probably not the correct term, I used it just to see if I was able to compile).

    The following is an example

    #include "format.h"
    #include 
    
    using format::FormatString;
    using format::FormatDict;
    
    int main()
    {
        std::cout << FormatString("The answer is %{x}") % FormatDict()("x", 42);
        return 0;
    }
    

    It is different from boost.format approach because uses named parameters and because the format string and format dictionary are meant to be built separately (and for example passed around). Also I think that formatting options should be part of the string (like printf) and not in the code.

    FormatDict uses a trick for keeping the syntax reasonable:

    FormatDict fd;
    fd("x", 12)
      ("y", 3.141592654)
      ("z", "A string");
    

    FormatString is instead just parsed from a const std::string& (I decided to preparse format strings but a slower but probably acceptable approach would be just passing the string and reparsing it each time).

    The formatting can be extended for user defined types by specializing a conversion function template; for example

    struct P2d
    {
        int x, y;
        P2d(int x, int y)
            : x(x), y(y)
        {
        }
    };
    
    namespace format {
        template<>
        std::string toString(const P2d& p, const std::string& parms)
        {
            return FormatString("P2d(%{x}; %{y})") % FormatDict()
                ("x", p.x)
                ("y", p.y);
        }
    }
    

    after that a P2d instance can be simply placed in a formatting dictionary.

    Also it's possible to pass parameters to a formatting function by placing them between % and {.

    For now I only implemented an integer formatting specialization that supports

    1. Fixed size with left/right/center alignment
    2. Custom filling char
    3. Generic base (2-36), lower or uppercase
    4. Digit separator (with both custom char and count)
    5. Overflow char
    6. Sign display

    I've also added some shortcuts for common cases, for example

    "%08x{hexdata}"
    

    is an hex number with 8 digits padded with '0's.

    "%026/2,8:{bindata}"
    

    is a 24-bit binary number (as required by "/2") with digit separator ":" every 8 bits (as required by ",8:").

    Note that the code is just an idea, and for example for now I just prevented copies when probably it's reasonable to allow storing both format strings and dictionaries (for dictionaries it's however important to give the ability to avoid copying an object just because it needs to be added to a FormatDict, and while IMO this is possible it's also something that raises non-trivial problems about lifetimes).

    UPDATE

    I've made a few changes to the initial approach:

    1. Format strings can now be copied
    2. Formatting for custom types is done using template classes instead of functions (this allows partial specialization)
    3. I've added a formatter for sequences (two iterators). Syntax is still crude.

    I've created a github project for it, with boost licensing.

提交回复
热议问题