如何在 clang++ 中干净地进行格式化字符串连接
How to cleanly do formatted string concatenation in clang++
我在 Windows 上使用 clang++
来做一些非常基本的 SDL2 东西,但我刚发现 <format>
没有附带 Clang++,也没有“fmt"开箱即用。
我需要的是一种更漂亮的方法来连接一堆格式化的字符串,这在其他地方是微不足道的,虽然我设法让它工作,但我对长时间重复的结构不满意。这是我得到的:
std::string getInfo() {
...
char ver[200] = "", verInfo[200] = "";
sprintf (ver, "Compiled using SDL version : %d.%d.%d \n", compiled.major, compiled.minor, compiled.patch); strcat_s (verInfo, ver);
sprintf (ver, "and linked with SDL version : %d.%d.%d \n", linked.major, linked.minor, linked.patch); strcat_s (verInfo, ver);
sprintf (ver, "and using SDL_TTF version : %d.%d.%d \n", ttfv.major, ttfv.minor, ttfv.patch); strcat_s (verInfo, ver);
return verInfo;
}
问:是否有更紧凑、更智能的方法,或许不使用 2 个缓冲区来做到这一点?
更新:
按照用户 Galik 的建议,通过在流处理程序中使用自定义结构,设法显着减少流代码。代码现在看起来像这样:
struct version_info {
int major, minor, patch;
friend std::ostream& operator<<(std::ostream& os, version_info const& v) {
os << v.major << '.' << v.minor << '.' << v.patch;
return os;
}
};
std::string getInfo() {
SDL_version aa;
SDL_version bb;
SDL_version cc;
SDL_VERSION(&aa);
SDL_GetVersion(&bb);
SDL_TTF_VERSION(&cc);
std::ostringstream oss;
oss << "SDL version : " << aa << '\n';
oss << "SDL linker : " << bb << '\n';
oss << "SDL_TTF ver. : " << cc << '\n';
return oss.str();
}
...但我现在遇到编译错误。
更新 2
使用inline
代替结构,解决问题:
inline std::ostream& operator<<(std::ostream& os, SDL_version const& v) {
os << int(v.major) << '.' << int(v.minor) << '.' << int(v.patch);
return os;
}
...
// same code
这样的事情可以接受吗?
// Old Way
std::string getInfo() {
char ver[200] = "", verInfo[200] = "";
sprintf (ver, "Compiled using SDL version : %d.%d.%d \n", compiled.major, compiled.minor, compiled.patch); strcat (verInfo, ver);
sprintf (ver, "and linked with SDL version : %d.%d.%d \n", linked.major, linked.minor, linked.patch); strcat (verInfo, ver);
sprintf (ver, "and using SDL_TTF version : %d.%d.%d \n", ttfv.major, ttfv.minor, ttfv.patch); strcat (verInfo, ver);
return verInfo;
}
// New Way
std::string getInfo2() {
std::ostringstream oss;
oss << "Compiled using SDL version : " << compiled.major << '.' << compiled.minor << '.' << compiled.patch << '\n';
oss << "and linked with SDL version : " << linked.major << '.' << linked.minor << '.' << linked.patch << '\n';
oss << "and using SDL_TTF version : " << ttfv.major << '.' << ttfv.minor << '.' << ttfv.patch << '\n';
return oss.str();
}
如果紧凑是您的目标,您可以通过为版本信息添加一个输出运算符友元函数来变得更聪明。
可能是这样的:
struct version_info
{
int major;
int minor;
int patch;
// formatting function for version_info objects.
friend std::ostream& operator<<(std::ostream& os, version_info const& v)
{
os << v.major << '.' << v.minor << '.' << v.patch;
return os;
}
};
// ... a few bytes later ...
std::string getInfo3() {
std::ostringstream oss;
oss << "Compiled using SDL version : " << compiled << '\n';
oss << "and linked with SDL version : " << linked << '\n';
oss << "and using SDL_TTF version : " << ttfv << '\n';
return oss.str();
}
对于格式化函数,术语friend用于使函数位于结构外部,因此它不是 成员函数 尽管它是在 struct 定义中声明的。
格式化函数参数是一个std::ostream& os
和一个用于打印的结构类型的对象。在这种情况下 version_info
。所以它需要一个你类型的对象 version_info
并将它打印到 os
.
每当你有命令 std::cout << compiled;
时,编译器都会用调用 格式化函数 来替换它,如下所示:
version_info compiled {2, 1, 0};
std::cout << compiled;
...变成...
version_info compiled {2, 1, 0};
operator<<(std::cout, compiled); // a call to your formatting function
但是如果您没有创建结构怎么办?
如果您使用来自其他库的版本信息,例如 SDL
,您将必须创建 输出函数 作为内联自由函数,如下所示:
#include <SDL2/SDL_version.h>
// ... a few bytes later ...
inline std::ostream& operator<<(std::ostream& os, SDL_version const& v)
{
os << int(v.major) << '.' << int(v.minor) << '.' << int(v.patch);
return os;
}
// ... a few bytes later ...
int main()
{
SDL_version compiled {2, 1, 0};
std::cout << compiled;
}
我在 Windows 上使用 clang++
来做一些非常基本的 SDL2 东西,但我刚发现 <format>
没有附带 Clang++,也没有“fmt"开箱即用。
我需要的是一种更漂亮的方法来连接一堆格式化的字符串,这在其他地方是微不足道的,虽然我设法让它工作,但我对长时间重复的结构不满意。这是我得到的:
std::string getInfo() {
...
char ver[200] = "", verInfo[200] = "";
sprintf (ver, "Compiled using SDL version : %d.%d.%d \n", compiled.major, compiled.minor, compiled.patch); strcat_s (verInfo, ver);
sprintf (ver, "and linked with SDL version : %d.%d.%d \n", linked.major, linked.minor, linked.patch); strcat_s (verInfo, ver);
sprintf (ver, "and using SDL_TTF version : %d.%d.%d \n", ttfv.major, ttfv.minor, ttfv.patch); strcat_s (verInfo, ver);
return verInfo;
}
问:是否有更紧凑、更智能的方法,或许不使用 2 个缓冲区来做到这一点?
更新:
按照用户 Galik 的建议,通过在流处理程序中使用自定义结构,设法显着减少流代码。代码现在看起来像这样:
struct version_info {
int major, minor, patch;
friend std::ostream& operator<<(std::ostream& os, version_info const& v) {
os << v.major << '.' << v.minor << '.' << v.patch;
return os;
}
};
std::string getInfo() {
SDL_version aa;
SDL_version bb;
SDL_version cc;
SDL_VERSION(&aa);
SDL_GetVersion(&bb);
SDL_TTF_VERSION(&cc);
std::ostringstream oss;
oss << "SDL version : " << aa << '\n';
oss << "SDL linker : " << bb << '\n';
oss << "SDL_TTF ver. : " << cc << '\n';
return oss.str();
}
...但我现在遇到编译错误。
更新 2
使用inline
代替结构,解决问题:
inline std::ostream& operator<<(std::ostream& os, SDL_version const& v) {
os << int(v.major) << '.' << int(v.minor) << '.' << int(v.patch);
return os;
}
...
// same code
这样的事情可以接受吗?
// Old Way
std::string getInfo() {
char ver[200] = "", verInfo[200] = "";
sprintf (ver, "Compiled using SDL version : %d.%d.%d \n", compiled.major, compiled.minor, compiled.patch); strcat (verInfo, ver);
sprintf (ver, "and linked with SDL version : %d.%d.%d \n", linked.major, linked.minor, linked.patch); strcat (verInfo, ver);
sprintf (ver, "and using SDL_TTF version : %d.%d.%d \n", ttfv.major, ttfv.minor, ttfv.patch); strcat (verInfo, ver);
return verInfo;
}
// New Way
std::string getInfo2() {
std::ostringstream oss;
oss << "Compiled using SDL version : " << compiled.major << '.' << compiled.minor << '.' << compiled.patch << '\n';
oss << "and linked with SDL version : " << linked.major << '.' << linked.minor << '.' << linked.patch << '\n';
oss << "and using SDL_TTF version : " << ttfv.major << '.' << ttfv.minor << '.' << ttfv.patch << '\n';
return oss.str();
}
如果紧凑是您的目标,您可以通过为版本信息添加一个输出运算符友元函数来变得更聪明。
可能是这样的:
struct version_info
{
int major;
int minor;
int patch;
// formatting function for version_info objects.
friend std::ostream& operator<<(std::ostream& os, version_info const& v)
{
os << v.major << '.' << v.minor << '.' << v.patch;
return os;
}
};
// ... a few bytes later ...
std::string getInfo3() {
std::ostringstream oss;
oss << "Compiled using SDL version : " << compiled << '\n';
oss << "and linked with SDL version : " << linked << '\n';
oss << "and using SDL_TTF version : " << ttfv << '\n';
return oss.str();
}
对于格式化函数,术语friend用于使函数位于结构外部,因此它不是 成员函数 尽管它是在 struct 定义中声明的。
格式化函数参数是一个std::ostream& os
和一个用于打印的结构类型的对象。在这种情况下 version_info
。所以它需要一个你类型的对象 version_info
并将它打印到 os
.
每当你有命令 std::cout << compiled;
时,编译器都会用调用 格式化函数 来替换它,如下所示:
version_info compiled {2, 1, 0};
std::cout << compiled;
...变成...
version_info compiled {2, 1, 0};
operator<<(std::cout, compiled); // a call to your formatting function
但是如果您没有创建结构怎么办?
如果您使用来自其他库的版本信息,例如 SDL
,您将必须创建 输出函数 作为内联自由函数,如下所示:
#include <SDL2/SDL_version.h>
// ... a few bytes later ...
inline std::ostream& operator<<(std::ostream& os, SDL_version const& v)
{
os << int(v.major) << '.' << int(v.minor) << '.' << int(v.patch);
return os;
}
// ... a few bytes later ...
int main()
{
SDL_version compiled {2, 1, 0};
std::cout << compiled;
}