我必须用sprintf格式化std::string,并将其发送到文件流。我该怎么做呢?


当前回答

Poco Foundation库有一个非常方便的格式函数,它在格式字符串和值中都支持std::string:

道格:http://pocoproject.org/docs/Poco.html # 7308 来源:https://github.com/pocoproject/poco/blob/develop/Foundation/src/Format.cpp

其他回答

c++ 17解决方案(这将工作于std::string和std::wstring):

分配一个缓冲区,格式化它,然后复制到另一个字符串是不高效的。可以创建格式化字符串大小的std::string,并直接格式化到字符串缓冲区中:

#include <string>
#include <stdexcept>
#include <cwchar>
#include <cstdio>
#include <type_traits>

template<typename T, typename ... Args>
std::basic_string<T> string_format(T const* const format, Args ... args)
{
    int size_signed{ 0 };

    // 1) Determine size with error handling:    
    if constexpr (std::is_same_v<T, char>) { // C++17
        size_signed = std::snprintf(nullptr, 0, format, args ...);
    }
    else {
        size_signed = std::swprintf(nullptr, 0, format, args ...);
    }  
    if (size_signed <= 0) {
        throw std::runtime_error("error during formatting.");
    }
    const auto size = static_cast<size_t>(size_signed);

    // 2) Prepare formatted string:
    std::basic_string<T> formatted(size, T{});
    if constexpr (std::is_same_v<T, char>) { // C++17
        std::snprintf(formatted.data(), size + 1, format, args ...); // +1 for the '\0' (it will not be part of formatted).
    }
    else {
        std::swprintf(formatted.data(), size + 1, format, args ...); // +1 for the '\0' (it will not be part of formatted).
    }

    return formatted; // Named Return Value Optimization (NRVO), avoids an unnecessary copy. 
}

此外:通常,format参数是char[] / wchar_t[] &创建std::string对象效率不高。传递char*或wchar_t* &如果你已经有一个std::string对象,你仍然可以使用它作为your_string.c_str()。例子:

int main()
{
    int i{ 0 };

    // The format parameter is a char[] / wchar_t[]:

    const std::string title1 = string_format("story[%d].", ++i); // => "story[1]"

    const std::wstring title2 = string_format(L"story[%d].", ++i); // => L"story[2]"

    // If you already have a std::string object:

    const std::string format1{ "story[%d]." };
    const std::string title3 = string_format(format1.c_str(), ++i); // => "story[3]"

    const std::wstring format2{ L"story[%d]." };
    const std::wstring title4 = string_format(format2.c_str(), ++i); // => L"story[4]"  
}

Boost::format()提供了你想要的功能:

Boost格式库简介如下:

format对象由format-string构造,然后通过反复调用运算符%来给出参数。 然后,每个参数都被转换为字符串,这些字符串又根据format-string组合成一个字符串。

#include <boost/format.hpp>

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
// prints "writing toto,  x=40.230 : 50-th try"

你不能直接这样做,因为你没有对底层缓冲区的写访问权(直到c++ 11;见Dietrich Epp的评论)。你必须先在c-string中执行,然后将其复制到std::string中:

  char buff[100];
  snprintf(buff, sizeof(buff), "%s", "Hello");
  std::string buffAsStdStr = buff;

但我不确定为什么不直接使用字符串流?我想你有特定的理由不这么做:

  std::ostringstream stringStream;
  stringStream << "Hello";
  std::string copyOfStr = stringStream.str();

String没有你需要的东西,但是std::stringstream有。使用stringstream创建字符串,然后提取字符串。这里有一个关于你可以做的事情的全面列表。例如:

cout.setprecision(10); //stringstream is a stream like cout

将在打印双精度或浮点数时提供10位小数点后的精度。

更新了一些答案,不同的是-函数将正确接受std::string为%s

namespace format_helper
{

    template <class Src>
    inline Src cast(Src v)
    {
        return v;
    }

    inline const char *cast(const std::string& v)
    {
        return v.c_str();
    }
};

template <typename... Ts>
inline std::string stringfmt (const std::string &fmt, Ts&&... vs)
{
    using namespace format_helper;
    char b;
    size_t required = std::snprintf(&b, 0, fmt.c_str(), cast(std::forward<Ts>(vs))...);//not counting the terminating null character.
    std::string result;
    //because we use string as container, it adds extra 0 automatically
    result.resize(required , 0);
    //and snprintf will use n-1 bytes supplied
    std::snprintf(const_cast<char*>(result.data()), required + 1, fmt.c_str(), cast(std::forward<Ts>(vs))...);

    return result;
}

生活:http://cpp.sh/5ajsv