如何在整数类型的模板函数中选择snprinf掩码?
How to choose snprinf mask in template function for integral type?
我有一个模板函数,它接受整数类型的参数并将其复制到堆栈上的字符数组 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"
mask reqiures 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
headers 会显着增加编译时间。也许有更好更简单的方法?
您可以使用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"; }
因为你是 "trying to avoid allocation" 并且你仍然在使用 boost:使用 Boost Iostreams 自定义设备
PS Lest it's not obvious, by using streams you get all the goodness:
- combine with Boost Format if you want printf style or positional argument format strings
- combine with Boost Locale for localized messages (
gettext
) and formatting (ordinals, dates, numerics, ...)
#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
以进一步优化。您可以根据需要重复使用该字符串,而不会产生更多分配。
#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";
}
以上两种用法都在 header-only 模式下使用 Boost Iostream(对 Boost(共享)库没有运行时依赖性)。
我有一个模板函数,它接受整数类型的参数并将其复制到堆栈上的字符数组 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"
mask reqiures 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
headers 会显着增加编译时间。也许有更好更简单的方法?
您可以使用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"; }
因为你是 "trying to avoid allocation" 并且你仍然在使用 boost:使用 Boost Iostreams 自定义设备
PS Lest it's not obvious, by using streams you get all the goodness:
- combine with Boost Format if you want printf style or positional argument format strings
- combine with Boost Locale for localized messages (
gettext
) and formatting (ordinals, dates, numerics, ...)
#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
以进一步优化。您可以根据需要重复使用该字符串,而不会产生更多分配。
#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";
}
以上两种用法都在 header-only 模式下使用 Boost Iostream(对 Boost(共享)库没有运行时依赖性)。