使用 make_string()
或 make_string_delim()
将对象格式化为字符串(加分隔符)再拼接起来,类似 Python 里的 str.join()
:
/**
* @brief Prints args to a string, without any delimiter
*/
template <typename... Args>
std::string make_string(const Args &... args) {
std::stringstream ss;
print(ss, args...);
return ss.str();
}
/**
* Creates std::string from arguments, as long as every element has `operator<<`
* defined for stream operation.
*
* If there's no `operator<<`, compiler will fire an error
*
* @param delimiter String, which will separate arguments in the final string
* @return Concatenated std::string
*/
template <typename Delimiter, typename... Args>
std::string make_string_delim(const Delimiter &delimiter, const Args &... args) {
std::stringstream ss;
print_delim(ss, delimiter, args...);
return ss.str();
}
/**
* This overload handles the edge case when no arguments are given and returns an empty string
*/
template <typename Delimiter>
std::string make_string_delim(const Delimiter &) {
return {};
}
上述函数模板基于 print()
和 print_delim()
实现。print()
和 print_delim()
是更一般的情况——输出到 std::ostream
:
struct no_delimiter {};
inline std::ostream &operator<<(std::ostream &os, no_delimiter) { return os; }
template <typename Delimiter>
void print_delim(std::ostream &os, const Delimiter &delimiter) {
// No-op
}
template <typename Delimiter, typename T>
void print_delim(std::ostream &os, const Delimiter &delimiter, const T &val) {
os << val;
}
/**
* @brief Populates stream with given arguments, as long as they have
* `operator<<` defined for stream operation
*/
template <typename Delimiter, typename T, typename... Args>
void print_delim(std::ostream &os, const Delimiter &delimiter, const T &val,
const Args &... args) {
os << val << delimiter;
print_delim(os, delimiter, args...);
}
/**
* @brief Populates stream with given arguments, as long as they have
* `operator<<` defined for stream operation
*/
template <typename... Args>
void print(std::ostream &os, const Args &... args) {
print_delim(os, no_delimiter(), args...);
}
另外还有用于方便打印 STL 容器的 join()
函数,以及借助它为 std::vector
和 std::array
实现的 operator<<
:
template <typename Collection, typename Delimiter>
std::ostream &join(std::ostream &os, const Collection &collection, const Delimiter &delim) {
bool first = true;
for (auto &element : collection) {
if (!first) {
os << delim;
} else {
first = false;
}
os << element;
}
return os;
}
template <typename Collection>
std::ostream &join(std::ostream &os, const Collection &collection) {
return join(os, collection, ", ");
}
template <typename T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &vec) {
return join(os, vec);
}
template <typename T, size_t N>
std::ostream &operator<<(std::ostream &os, const std::array<T, N> &arr) {
return join(os, arr);
}
参考:NVIDIA DALI 源码仓库下的
include/dali/core/format.h
。