Home > front end >  Create string according to the parameter pack arguments count
Create string according to the parameter pack arguments count

Time:09-10

I have a function with a parameter pack, I pass this pack to the fmt::format function, and I want to create a formatStr according to the args count, meaning add "{}#" for each passed argument.

I can do it using iterating, but is it possible to do this with one line solution? How to do it gracefully?

    template <typename... Args>
    void formatArgs( Args&&...args)
    {
        const auto size = sizeof...(Args);
        std::string formatStr = ...// "{}#{}#{}..." - {}# should depend on args count
        
        /* 
        std::ostringstream formatStr;
        for (const auto& p : { args... })
            formatStr << {}#";
        */
    
        auto res = fmt::format(formatStr.c_str(), args...);
        ...
    }

CodePudding user response:

An ugly fold expression would work. It's only redeeming quality is that it's just one line, and in C 20 it should be a constexpr, so in C 20 this'll wind up to be a single std::string constructor call:

#include <string>
#include <iostream>

template<typename ...Args>
std::string string_from_args(Args && ...args)
{
    return std::string{ ((args, std::string{"%s#"})   ...) };
}

int main()
{
    std::cout << string_from_args(1, 2, 3, 4) << "\n";

    return 0;
}

CodePudding user response:

If you want to create a string with all the arguments I suggest you use an std::ostringstream to create the string directly instead of going through std::format or similar.

How to create the string differs between version of C . Before C 17 and pre-fold you can use overloading of functions to handle the argument packs:

// Handle single-argument string construction
template<typename Arg>
std::string string_from_args(Arg&& arg)
{
    return (std::ostringstream() << arg).str();
}

// Handle multiple-argument string construction
template<typename First, typename ...Rest>
std::string string_from_args(First&& first, Rest&& ...rest)
{
    return (std::ostringstream() << string_from_args(first) << '#' << string_from_args(rest...)).str();
}

Then with fold-expressions introduced in C 17:

template<typename ...Args>
std::string string_from_args(Args&& ...args)
{
    char const* separator = "";
    std::ostringstream os;
    (((os << separator << args), separator = "#"), ...);
    return os.str();
}

With a simple main function

int main()
{
    std::cout << string_from_args(123, 456.789, "foo", 'b');
}

both variants should construct and print the string

123#456.789#foo#b
  • Related