boost::format with variadic template arguments

后端 未结 3 1362
隐瞒了意图╮
隐瞒了意图╮ 2021-01-12 03:37

Suppose I have a printf-like function (used for logging) utilizing perfect forwarding:

template
void awesome_printf         


        
相关标签:
3条回答
  • 2021-01-12 04:18

    I did some googling and found an interesting solution:

    #include <iostream>
    #include <boost/format.hpp>
    
    template<typename... Arguments>
    void format_vargs(std::string const& fmt, Arguments&&... args)
    {
        boost::format f(fmt);
        int unroll[] {0, (f % std::forward<Arguments>(args), 0)...};
        static_cast<void>(unroll);
    
        std::cout << boost::str(f);
    }
    
    int main()
    {
        format_vargs("%s %d %d", "Test", 1, 2);
    }
    

    I don't know if this is a recommended solution but it seems to work. I don't like the hacky static_cast usage, which seems necessary to silence the unused variable warnings on GCC.

    0 讨论(0)
  • 2021-01-12 04:20

    As is usual with variadic templates, you can use recursion:

    std::string awesome_printf_helper(boost::format& f){
        return boost::str(f);
    }
    
    template<class T, class... Args>
    std::string awesome_printf_helper(boost::format& f, T&& t, Args&&... args){
        return awesome_printf_helper(f % std::forward<T>(t), std::forward<Args>(args)...);
    }
    
    template<typename... Arguments>
    void awesome_printf(std::string const& fmt, Arguments&&... args)
    {
        boost::format f(fmt);
    
        auto result = awesome_printf_helper(f, std::forward<Arguments>(args)...);
    
        // call BlackBoxLogFunction with result as appropriate, e.g.
        std::cout << result;
    }
    

    Demo.


    In C++17, simply (f % ... % std::forward<Arguments>(args)); will do.

    0 讨论(0)
  • 2021-01-12 04:25

    Just to summarize the void.pointer's solution and the hints proposed by Praetorian, T.C. and Jarod42, let me provide the final version (online demo)

    #include <boost/format.hpp>
    #include <iostream>
    
    template<typename... Arguments>
    std::string FormatArgs(const std::string& fmt, const Arguments&... args)
    {
        boost::format f(fmt);
        std::initializer_list<char> {(static_cast<void>(
            f % args
        ), char{}) ...};
    
        return boost::str(f);
    }
    
    int main()
    {
        std::cout << FormatArgs("no args\n"); // "no args"
        std::cout << FormatArgs("%s; %s; %s;\n", 123, 4.3, "foo"); // 123; 4.3; foo;
        std::cout << FormatArgs("%2% %1% %2%\n", 1, 12); // 12 1 12
    }
    

    Also, as it was noted by T.C., using the fold expression syntax, available since C++17, the FormatArgs function can be rewritten in the more succinct way

    template<typename... Arguments>
    std::string FormatArgs(const std::string& fmt, const Arguments&... args)
    {
        return boost::str((boost::format(fmt) % ... % args));
    }
    
    0 讨论(0)
提交回复
热议问题