Search code examples
c++c++17variadic-templatesfold-expression

How to make grouped or paired fold of parameter pack?


template<class Msg, class... Args>
std::wstring descf(Msg, Args&&... args) {
    std::wostringstream woss;

    owss << Msg << ". " << ... << " " << args << ": '" << args << "' ";//not legal at all

    //or

    owss << Msg << ". " << args[0] << ": '" << args[1] << "'  " << args[2] << ": '" << args[3] << "' "; //... pseudo code, and so on...
}

I know I can just use a list of pairs or something like that instead, but I'm interested in how to do this while keeping the syntax of the function to:

const auto formatted = descf(L"message", "arg1", arg1, "arg2", arg2);

Solution

  • You can use a fold expression! It's not the prettiest*, but it's shorter than all the non-fold solutions presented:

    template<class T, class ... Args>
    std::wstring descf(T msg, Args&&... args) {
        std::wostringstream owss;
        owss << msg << ". ";
    
        std::array<const char*, 2> tokens{": '", "' "};
        int alternate = 0;
        ((owss << args << tokens[alternate], alternate = 1 - alternate), ...);
    
        return owss.str();
    }
    

    Demo with sample output: https://godbolt.org/z/Gs8d2x

    We perform a fold over the comma operator, where each operand is an output of one args and the alternating token, plus switching the token index (the latter two are combined with another comma operator).

    *To a reader familiar with fold expressions (and the comma operator) this is probably the "best" code, but for everyone else it's utter gibberish, so use your own judgement whether you want to inflict this on your code base.