我应该如何删除可变函数?
how should I remove variadic functions?
我读到可变参数函数不是好的编码。
我有一个非常旧的框架,其中包含一些可变参数函数我想删除可变参数以保留调试功能。
DEBUG(wchar_t* text, ...)
此调试函数使用相同的字符串 sintaxis %d、%f...等调用类似 printf 的函数。
正确的方法应该是什么?
由于您标记了问题 c++
,您可以基于 c++
流创建一个新的 class/function - 甚至可以更改 'old' 系统以使用您的新的一个。然后 随着时间的推移 迁移到那个系统,也许在某个时候你可以摆脱旧的(在你的情况下是 'DEBUG')。
令人惊讶的是,我建议保留调试功能,除非您愿意将整个接口更改为 C++ IO 方式,也就是流。如果您要使用 printf
和 printf
语法,请按原样使用。否则一路现代化。
例如,让我们保持你的实施是沿着这条线的某个地方:
void dbg(char* txt, ...)
{
va_list args;
va_start(args, txt);
vprintf(txt, args);
va_end(arts);
}
是的,有摆脱可变参数的选项,但如果您要保留 printf
系列语法,那么这样做的好处为 0:
template <class... Args>
auto dbg(const char* fmt, const Args&... args)
{
printf(fmt, args...);
}
然后你意识到 char*
比 C++
多 C
然后你改为:
template <class... Args>
auto dbg(const std::string& fmt, const Args&... args)
{
printf(fmt.c_str(), args...);
}
然后您意识到 printf
比 C++
更多 C
,现在的选择是摆脱 printf
并完全废弃它。
这个问题 How to make a variadic macro for std::cout? 向您展示了一种方法,如果您仍然设置在函数上:
template<typename ...Args>
void log(Args && ...args)
{
(std::cout << ... << args);
}
另一种选择是制作这样的东西:
log << "this is the " << i << " log";
但是让它在末尾添加一个换行符并不是微不足道的。
最后,我认为最好的解决方案是使用日志记录库。
我同意@bolov 的建议,让调试功能保持原样。
然而,您可以使用 std::initializer_list
和 std::variant
(C++17 起) 类型。
下面是一个尚未处理格式说明符但可以提供一些改进方法的想法的小示例。
#include <iostream>
#include <cstdlib>
#include <variant>
typedef std::variant<std::string, int, float, bool> DebugOutParam;
std::ostream& operator << (std::ostream& os, const DebugOutParam& v)
{
if (std::holds_alternative<std::string>(v))
os << std::get<std::string>(v);
else if (std::holds_alternative<int>(v))
os << std::get<int>(v);
else if (std::holds_alternative<float>(v))
os << std::get<float>(v);
else if (std::holds_alternative<bool>(v))
os << (std::get<bool>(v) ? "true" : "false");
else
os << "?Unsupported?";
return os;
}
typedef std::initializer_list<DebugOutParam> DebugOutParams;
void dbg(std::string fmt, DebugOutParams l)
{
std::cout << fmt << ": ";
for (DebugOutParams::const_iterator it = l.begin(); it != l.end(); it++)
{
DebugOutParam v = *it;
std::cout << (it == l.begin() ? "" : ", ") << v;
}
std::cout << std::endl;
}
int main()
{
dbg("Test", {123, std::string("456"), true, static_cast<float>(456.789)});
}
输出
Test: 123, 456, true, 456.789
我读到可变参数函数不是好的编码。
我有一个非常旧的框架,其中包含一些可变参数函数我想删除可变参数以保留调试功能。
DEBUG(wchar_t* text, ...)
此调试函数使用相同的字符串 sintaxis %d、%f...等调用类似 printf 的函数。
正确的方法应该是什么?
由于您标记了问题 c++
,您可以基于 c++
流创建一个新的 class/function - 甚至可以更改 'old' 系统以使用您的新的一个。然后 随着时间的推移 迁移到那个系统,也许在某个时候你可以摆脱旧的(在你的情况下是 'DEBUG')。
令人惊讶的是,我建议保留调试功能,除非您愿意将整个接口更改为 C++ IO 方式,也就是流。如果您要使用 printf
和 printf
语法,请按原样使用。否则一路现代化。
例如,让我们保持你的实施是沿着这条线的某个地方:
void dbg(char* txt, ...)
{
va_list args;
va_start(args, txt);
vprintf(txt, args);
va_end(arts);
}
是的,有摆脱可变参数的选项,但如果您要保留 printf
系列语法,那么这样做的好处为 0:
template <class... Args>
auto dbg(const char* fmt, const Args&... args)
{
printf(fmt, args...);
}
然后你意识到 char*
比 C++
多 C
然后你改为:
template <class... Args>
auto dbg(const std::string& fmt, const Args&... args)
{
printf(fmt.c_str(), args...);
}
然后您意识到 printf
比 C++
更多 C
,现在的选择是摆脱 printf
并完全废弃它。
这个问题 How to make a variadic macro for std::cout? 向您展示了一种方法,如果您仍然设置在函数上:
template<typename ...Args>
void log(Args && ...args)
{
(std::cout << ... << args);
}
另一种选择是制作这样的东西:
log << "this is the " << i << " log";
但是让它在末尾添加一个换行符并不是微不足道的。
最后,我认为最好的解决方案是使用日志记录库。
我同意@bolov 的建议,让调试功能保持原样。
然而,您可以使用 std::initializer_list
和 std::variant
(C++17 起) 类型。
下面是一个尚未处理格式说明符但可以提供一些改进方法的想法的小示例。
#include <iostream>
#include <cstdlib>
#include <variant>
typedef std::variant<std::string, int, float, bool> DebugOutParam;
std::ostream& operator << (std::ostream& os, const DebugOutParam& v)
{
if (std::holds_alternative<std::string>(v))
os << std::get<std::string>(v);
else if (std::holds_alternative<int>(v))
os << std::get<int>(v);
else if (std::holds_alternative<float>(v))
os << std::get<float>(v);
else if (std::holds_alternative<bool>(v))
os << (std::get<bool>(v) ? "true" : "false");
else
os << "?Unsupported?";
return os;
}
typedef std::initializer_list<DebugOutParam> DebugOutParams;
void dbg(std::string fmt, DebugOutParams l)
{
std::cout << fmt << ": ";
for (DebugOutParams::const_iterator it = l.begin(); it != l.end(); it++)
{
DebugOutParam v = *it;
std::cout << (it == l.begin() ? "" : ", ") << v;
}
std::cout << std::endl;
}
int main()
{
dbg("Test", {123, std::string("456"), true, static_cast<float>(456.789)});
}
输出
Test: 123, 456, true, 456.789