简体   繁体   English

使用模板variadic函数将多个参数传递给另一个函数

[英]pass multiple arguments to another function using template variadic function

Let us consider the following function: 让我们考虑以下功能:

static void Print(const Type& type, const std::string& message, const std::string& variable) {
    Log(type, message + ": " + variable);
}

I'd like it to pass arbitrary number of variables (I mean std::string & variable - this holds a variable name) and then send them via Log() function together and for this reason, I've considered using template variadic function (an overloaded Print() ). 我希望它传递任意数量的变量(我的意思是std::string & variable - 它保存一个变量名),然后通过Log()函数一起发送它们,因此我考虑使用模板可变参数函数(重载的Print() )。 I'd define it like this: 我这样定义它:

template <typename Arg, typename ...Args)
static void Print(const Type& type, const std::string& message,
                  const Arg& arg, const Args&... args);

and then: 接着:

Print(type, message, args...);
Log(type, message + ": " + arg);

Just an idea, this would work most likely like this: 只是一个想法,这很可能会像这样:

  • args... would be passed and Print() function would be called recursively until there's no arguments left, args...将被传递, Print()函数将被递归调用,直到没有参数为止,
  • but at the same time, Log() function would be called which would basically log it every time. 但同时,将调用Log()函数,它基本上每次都会记录它。

What I would need to do is to somehow remember arg value but it would require calling Print() with an additional argument and I don't really like this idea. 我需要做的是以某种方式记住arg值,但它需要使用另一个参数调用Print() ,我真的不喜欢这个想法。 Do you have any other clues? 你还有其他线索吗?

Depending on the desired format, you might be able to get away with a fold expression: 根据所需的格式,您可以使用折叠表达式:

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());
}

Demo 演示

It seems to me that the Max Langhof's solution is simple and elegant. 在我看来,Max Langhof的解决方案简单而优雅。

Unfortunately it uses template folding that is available only starting from C++17. 不幸的是,它使用的模板折叠仅从C ++ 17开始提供。

I propose a C++11/C++14 version that, instead template folding, uses the old trick of the initialization of an unused array 我提出了一个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());
 }

I simplified your example a bit, so assuming I correctly understood what you want to do, you can do one of the 2 following solutions, if the C++17 folds suggested by @Max Langhof are not supported by your compiler. 我简化了你的例子,所以假设我正确地理解你想做什么,你可以做以下两个解决方案之一,如果你的编译器不支持@Max Langhof建议的C ++ 17折叠。

Both of them work on any type that supports operator+ for doing the correct thing, but are simple to modify if your concat function is something else. 它们都可以在任何支持operator +的类型上运行,但是如果你的concat函数是其他东西,它们很容易修改。

Option 1, recursive unpacking: 选项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...);
}

Option 2, unpacking into a std:vector: 选项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);
}

Be aware that this version will create copies of the arguments within the std::vector, unlike the other solution which will not. 请注意,此版本将在std :: vector中创建参数的副本,而不像其他解决方案那样。

Both examples can be used in the following fashion: 这两个示例都可以按以下方式使用:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM