使用模板可变参数函数将多个参数传递给另一个函数
pass multiple arguments to another function using template variadic function
让我们考虑以下函数:
static void Print(const Type& type, const std::string& message, const std::string& variable) {
Log(type, message + ": " + variable);
}
我希望它传递任意数量的变量(我的意思是std::string &
变量 - 它包含一个变量名称(,然后通过Log()
函数将它们一起发送,出于这个原因,我考虑使用模板可变参数函数(重载Print()
(。我会这样定义它:
template <typename Arg, typename ...Args)
static void Print(const Type& type, const std::string& message,
const Arg& arg, const Args&... args);
然后:
Print(type, message, args...);
Log(type, message + ": " + arg);
只是一个想法,这很可能是这样的:
args...
将被传递,并且Print()
函数将被递归调用,直到没有参数,- 但与此同时,
Log()
函数将被调用,该函数基本上每次都会记录它。
我需要做的是以某种方式记住arg
值,但这需要用额外的参数调用Print()
,我真的不喜欢这个想法。你还有其他线索吗?
在我看来,Max Langhof的解决方案简单而优雅。
不幸的是,它使用仅从 C++17 开始可用的模板折叠。
我提出了一个 C++11/C++14 版本,而不是模板折叠,使用初始化未使用数组的旧技巧
template <typename ... Args>
void Print (Type const & type, std::string const & message,
Args const & ... arg)
{
using unused = int[];
std::stringstream strstr;
strstr << message << ": ";
(void)unused { 0, (strstr << arg << ", ", 0)... };
std::string toLog = strstr.str();
// Remove last separator characters.
toLog.erase(toLog.end() - 2, toLog.end());
Log(type, strstr.str());
}
根据所需的格式,您可能可以使用折叠表达式:
template<class... Args>
void Print(const Type& type, const std::string& message, const Args&... arg)
{
std::stringstream strstr;
strstr << message << ": "; // Or your prefix computation, whatever you want.
((strstr << arg << ", "), ...);
std::string toLog = strstr.str();
// Remove last separator characters.
toLog.erase(toLog.end() - 2, toLog.end());
Log(type, strstr.str());
}
演示
我稍微简化了你的示例,所以假设我正确理解了你想要做什么,如果你的编译器不支持 @Max Langhof 建议的 C++17 折叠,你可以执行以下 2 个解决方案之一。
它们都适用于任何支持 operator+ 以执行正确操作的类型,但如果您的 concat 函数是其他函数,则很容易修改。
选项 1,递归解包:
template <typename Arg>
static void Print(const Arg& message, const Arg& arg1)
{
Log(message + ": " + arg1);
}
template <typename Arg, typename... Args>
static void Print(const Arg& message, const Arg& arg1, const Arg& arg2, const Args&... variables)
{
Print(message, arg1 + ", " + arg2, variables...);
}
选项 2,解包成 std:vector:
template <typename Arg, typename... Args>
static void Print2(const Arg& message, const Arg& arg1, const Args&... variables)
{
std::vector<Arg> args = { variables... };
Arg result = std::accumulate(args.begin(), args.end(), arg1, [](const Arg& a, const Arg& b) {
return a + ", " + b;});
Log(message + ": " + result);
}
请注意,此版本将在 std::vector 中创建参数的副本,而其他解决方案不会。
这两个示例都可以按以下方式使用:
static void Log(const std::string& m)
{
std::cout << m << std::endl;
}
int main()
{
std::string msg = "MyMessage1";
std::string var1 = "Var1";
std::string var2 = "Var2";
std::string var3 = "Var3";
std::string var4 = "Var4";
std::string var5 = "Var5";
Print(msg, var1);
Print(msg, var1, var2);
Print(msg, var1, var2, var3);
Print(msg, var1, var2, var3, var4);
Print(msg, var1, var2, var3, var4, var5);
}
相关文章:
- 如何在C++中将迭代器作为函数参数传递
- 为什么我不能将引用作为 std::async 的函数参数传递
- 节点插件 API 将数组作为函数参数传递
- 将字符串数组作为函数参数传递
- 如何通过 C++ 中的函数参数传递初始值设定项列表的固定大小的初始值设定项列表?
- 我可以动态创建新地图并作为函数参数传递吗?
- 将任意模板向量作为函数参数C++传递
- 将函数指针作为函数参数传递的目的
- C++:通过函数参数传递的值给出不同的结果
- 当数组大小在C++中未知时,如何在运行时将对字符串数组的引用作为函数参数传递?
- 通过宏将函数参数传递给函数
- C++:访问作为函数参数传递的双指针数组所指向的变量的值
- 如何将 std::string 作为构造函数参数传递,并将其保存的 C 字符串存储在 void 指针中?
- 将派生类构造函数参数传递给受保护的成员
- 将指向数组的指针作为函数参数传递,这本身就是另一个函数的返回值?
- 如何将二维数组类型字符(字符串)作为函数参数传递?
- 有什么理由C++ 11+ std::mutex 应该声明为全局变量,而不是作为函数参数传递到 std::thread 中
- 如何将派生类作为函数参数传递:如果派生类成员不在父类中怎么办
- 如何将变量作为构造函数参数或函数参数传递
- 当数组对象以函数参数传递时,为什么复制构造函数会自称