C++格式化字符串的一个极简实现

First Post:

Blog Link:

写C++程序设计的大作业时,不方便引用外部的库,想传递一些格式化字符串写起来就很麻烦。一般来说使用sprintf或者std::ostringstream,但前者一般只支持C原生类型,而后者通常的写法略显繁琐(前者也比较繁琐)。于是便想到了下面的写法:

1
2
#define format(__stream)\
(dynamic_cast<std::ostringstream & >(std::ostringstream() __stream).str())

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
namespace crz {

class bad_comparison : public std::logic_error {
public:
explicit bad_comparison(
const std::type_info &from,
const std::type_info &to,
const char *opt) :
std::logic_error(format(<< from.name() << " " << opt << " " << to.name())) {}
};

}

还可以用变参模板实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace crz {

namespace detail {

template<typename ...Args, typename = typename std::enable_if<sizeof...(Args) == 0>::type>
inline std::ostream &__va_output(std::ostream &os, Args &&...args) {
return os;
}
template<typename T, typename ...Args>
inline std::ostream &__va_output(std::ostream &os, T &&t, Args &&...args) {
os << t;
return __va_output(os, std::forward<Args>(args)...);
}

}

template<typename ...Args>
inline std::string format(Args &&...args) {
std::ostringstream os;
detail::__va_output(os, std::forward<Args>(args)...);
return os.str();
}

}

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
namespace crz {

class bad_comparison : public std::logic_error {
public:
explicit bad_comparison(
const std::type_info &from,
const std::type_info &to,
const char *opt) :
std::logic_error(format(from.name(), " ", opt, " ", to.name())) {}
};

}

不过变参模板的实现显然没有之前用宏实现来得简洁。

以上只是个人一时的脑洞,较大的项目还是用fmt等成熟的格式化库为好(或者等有生之年C++20的format落地后用标准库)。