Skip to content

Instantly share code, notes, and snippets.

@AtomicVar
Created December 3, 2023 09:32
Show Gist options
  • Save AtomicVar/9ac547e76c266a59b8f4d40d54aa10ec to your computer and use it in GitHub Desktop.
Save AtomicVar/9ac547e76c266a59b8f4d40d54aa10ec to your computer and use it in GitHub Desktop.
一些用于格式化字符串的工具函数(来自 NVIDIA DALI)

使用 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::vectorstd::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);
}
@AtomicVar
Copy link
Author

参考:NVIDIA DALI 源码仓库下的 include/dali/core/format.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment