我修改了https://en.cppreference.com/w/cpp/language/parameter_pack中的示例,以便将字符串保存在变量中。我的代码
#include <string>
void tprintf(std::string& str, const std::string& format)
{
str += format;
}
template <typename T, typename... Targs>
void tprintf(std::string& str, const std::string& format, T arg, Targs ...Fargs)
{
for ( int i = 0; i < format.size(); i++ )
{
if ( format.at(i) == '%' )
{
if (format.at(i + 1) == 'd')
{
std::cout << "== 'd' -variable = " << arg << std::endl;
str += std::to_string(arg);
}
else if (format.at(i + 1) == 's')
{
std::cout << "== 's'" << std::endl;
str += arg;
}
tprintf(str, (i + 2 < format.size() ? format.substr(i + 2) : ""), Fargs...);
break;
}
str += format.at(i);
}
}
int main()
{
std::string str;
int age = 24;
std::string name("Hugo");
tprintf(str, "Name: %s, age: %d years\n", name, age);
std::cout << "result = " << str << std::endl;
}在编译代码时,我得到以下错误:
error: no matching function for call to ‘to_string(std::__cxx11::basic_string<char>&)’
str += std::to_string(arg);我认为参数包扩展到
tprintf(std::string&, const std::string&, std::string, int) <- arg是std::stringtprintf(std::string&, const std::string&, int) <- arg是int,我可以调用std::to_string(arg),但似乎arg还有比int (std::string或其他什么)更多的类型?当我删除std::to_string调用时,我会得到一些神秘的字符。如何将年龄的值转换为string并将其附加到str
发布于 2021-05-09 20:57:34
tprintf( std::string &,const::string&,std::string,int) <- arg是std::
因此,这里是正确的:
str += std::to_string(arg);arg是一个std::string,并且没有这样的std::to_string重载。
无论T是什么类型,生成的模板都必须是有效的C++代码。即使对应的格式化字符是d,函数中的所有内容都必须是有效的C++代码。
一般来说,尝试在类型安全的printf中实现C风格的C++格式没有多大意义.您已经知道需要格式化什么,这仅仅是因为您知道相应参数的类型。
在C样式的printf字符串中有不同的格式说明符,比如%s或%d,唯一的原因是这个C函数不知道作为参数传递给它的是什么,所以它依赖于实际的格式说明符来知道它是什么。
显然,C++的情况并非如此。您的格式说明符本身可以是一个%,没有其他任何东西。你很清楚什么参数会被传递进来。因此,只定义三个重载函数要简单得多:
template <typename... Targs>
void tprintf(std::string& str, const std::string& format, int arg, Targs ...args)
{
// Just the code that formats an int
}
template <typename... Targs>
void tprintf(std::string& str, const std::string& format, const std::string &arg, Targs ...args)
{
// Just the code that formats a std::string
}
void tprintf(std::string& str, const std::string& format)
{
// Nothing more to format, just adds everything else in "format" to "str".
}在前两种情况下,只需要自己搜索format以查找第一个%位置持有者,将之前的所有内容复制到str中,然后再使用格式化的参数,然后递归地用剩余的args重新调用tprintf,以及format中剩下的内容。
使用转发引用,"Targs && ...args“与std::forward一起将是后续的调整。
发布于 2021-05-09 21:00:46
if语句的所有分支都已编译。编译器试图将字符串参数传递给string,并且不存在重载。
它不会在运行时发生这一事实与此无关。在编译时,编译器需要知道
tprintf(str, "Name: %s, age: %d years\n", name, age);和是什么?
tprintf(str, "Name: %d, age: %d years\n", name, age);就行了。
考虑不包括两次类型信息。您已经知道名称是字符串,年龄是整数,在格式字符串中重复它是没有意义的。
我建议使用格式字符串的位置命令,因为这也使得本地化更加实用。
https://stackoverflow.com/questions/67462117
复制相似问题