如何在积分类型的模板函数中选择snprinf掩码

How to choose snprinf mask in template function for integral type?

本文关键字:函数 选择 掩码 snprinf 类型      更新时间:2023-10-16

我有一个模板函数,它接受一个整型参数,并将其复制到具有std::snprintf:的堆栈上的字符数组中

static const size_t size = 256;
char buffer[size];
template <class T, std::enable_if<std::is_integral<T>::value, T>::type>
bool to_array(T integer) {
  auto ret = std::snprint(buffer, size, "%lld", integer);
  return ret > 0;
}

问题是,例如,如果此函数与int类型一起使用,编译器会打印警告,即"%lld"掩码需要long long int类型。

为了修复它,我使用了boost::fusion::map:

using bf = boost::fusion;
using integral_masks = bf::map<
  bf::pair<char, const char*>,
  bf::pair<short, const char*>,
  ....
  bf::pair<unsigned long long, const char*>
>;
integral_masks masks(
  bf::make_pair<char>("%c"),
  bf::make_pair<int>("%d"),
  ....
  bf::make_pair<unsigned long>("%lu")
  bf::make_pair<unsigned long long>("%llu")
);
auto ret = std::snprint(buffer, size, bf::at_key<T>(masks), integer);

这是可行的,但它看起来有点重,并且boost::fusion标头显著增加了编译时间。也许有更好更简单的方法可以做到这一点?

由于您"试图避免分配",并且您无论如何都在使用boost:使用boost Iostreams自定义设备

PS为了避免不明显,使用流可以获得所有好处:

  • 如果需要printf样式或位置参数格式字符串,请与Boost Format组合使用
  • 与Boost Locale结合用于本地化消息(gettext)和格式设置(序数、日期、数字…)

在Coliru上直播

#include <array>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
namespace io = boost::iostreams;
int main()
{
    std::array<char, 128> buf;
    auto b = buf.begin(), e = buf.end();
    io::array_sink as(b, e);
    io::stream<io::array_sink> os(as);
    os << '1' << uint16_t(42) << uint32_t(42) << std::showbase << std::hex << int64_t(-1) << "n" 
       << std::boolalpha << false << "n"
       << std::numeric_limits<double>::infinity();
    std::cout << "result '" << std::string(b, os.tellp()) << "'n";
}

这将在buf已填充之后停止写入输出。

实际上,您可能只想要back_inserter。通过这种方式,你可以两全其美:控制分配,同时不受任意限制。

另请参阅std::string::reserve以了解进一步的优化。您可以随心所欲地重用该字符串,而不会产生更多的分配。

在Coliru上直播

#include <array>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
namespace io = boost::iostreams;
int main()
{
    std::string buf;
    io::stream<io::back_insert_device<std::string> > os(io::back_inserter(buf));
    os << '1' << uint16_t(42) << uint32_t(42) << std::showbase << std::hex << int64_t(-1) << "n" 
       << std::boolalpha << false << "n"
       << std::numeric_limits<double>::infinity();
    os.flush();
    std::cout << "result '" << buf << "'n";
}

以上两种使用都在仅标头模式下使用Boost Iostreams(在运行时不依赖于Boost(共享)库)。

您可以使用constexpr函数:

constexpr const char* format_of(char) { return "%c"; }
constexpr const char* format_of(int) { return "%d"; }
constexpr const char* format_of(unsigned long) { return "%lu"; }
constexpr const char* format_of(unsigned long long) { return "%llu"; }

实例