C++ 如何编写接受无限参数的函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9040617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:13:33  来源:igfitidea点击:

How do I write functions that accept unlimited arguments?

c++functionvariablesparametersarguments

提问by Trevor Hickey

I have only been able to find oneway for functions to take a variable amount of arguments.
It's this way:

我只能找到一种方法来让函数接受可变数量的参数。
是这样的:

#include <iostream>
#include <stdarg.h>

using namespace std;

void Print(int argumentAmount, ... );

int main()
{
    Print(5,11,22,33,44,55);
}

void Print(int argumentAmount, ... ){

    va_list arguments; 
    va_start(arguments, argumentAmount);

    int parameter;
    for(int i = 0; i < argumentAmount; ++i ){
        parameter = va_arg(arguments, int);
        cout << parameter << endl;
    }

    va_end(arguments);
    return;
}

2 Problems:
1.)I have to specify how many arguments I'm sending in- not desirable
2.)I can't figure out how to modify it so it will output strings.

2 问题:
1.)我必须指定我要发送多少个参数 - 不需要
2.)我不知道如何修改它以便输出字符串。

Would something like this be possible without having to overload the function multiple times:

无需多次重载函数,这样的事情是否可能成为可能:

void Output(/*not sure how this would look*/);

int main(){

    Output("hello","world");
    Output("this","is","a","test");
    Output("As","many","strings","as","you","want","may","be","passed","in");

    return 0;
}
void Output(/*not sure how this would look*/){

    //loop through each string passed in and output it
}

What about this:

那这个呢:

void Capitalize(/*all passed by reference*/);

int main(){

    string s1 = "hello";
    string s2 = "world";

    string s3 = "this";
    string s4 = "is";
    string s5 = "a";
    string s6 = "test";

    string s7 = "as";
    string s8 = "many";
    string s9 = "strings";
    string s10 = "as";
    string s11 = "you";
    string s12 = "want";

    Capitalize(s1,s2);
    Capitalize(s3,s4,s5,s6);
    Capitalize(s7,s8,s9,s10,s11,s12);

    return 0;
}
void Capitalize(/*all passed by reference*/){

    //capitalize each string passed in

}

All I can think to do is:
-overload the function multiple times
-have the function accept some type of container instead

我能想到的就是: -
多次
重载函数 - 让函数接受某种类型的容器

If this is NOT POSSIBLE, could someone explain why the compiler is not capable of accomplishing a task like this.

如果这不是 POSSIBLE,有人可以解释为什么编译器不能完成这样的任务。

回答by Alexey Kukanov

With variadic templates in C++11, you can do something like this (see the result at ideone)

使用 C++11 中的可变参数模板,你可以做这样的事情(见ideone 的结果

#include <string>
#include <iostream>

void Output() {
    std::cout<<std::endl;
}

template<typename First, typename ... Strings>
void Output(First arg, const Strings&... rest) {
    std::cout<<arg<<" ";
    Output(rest...);
}

int main() {
    Output("I","am","a","sentence");
    Output("Let's","try",1,"or",2,"digits");
    return 0;
}

回答by koblas

Quick and simple answer.

快速而简单的答案。

For C++ you need to specify either the number of arguments or a sentinel value to indicate the end of arguments.

对于 C++,您需要指定参数的数量或指示参数结束的标记值。

Your first example is a good example of specing the count, you could also do:

您的第一个示例是指定计数的一个很好的示例,您还可以执行以下操作:

void Print(const char *arg, ... ){
    va_list arguments;

    for (va_start(arguments, arg); arg != NULL; arg = va_arg(arguments, const char *)) {
        cout << arg << endl;
    }

    va_end(arguments);
}

Where your calling convention is:

您的调用约定在哪里:

Print("foo","bar",NULL);

If you want to take it to the next level, you can mix in a bit of the C Preprocessor and do:

如果你想把它提升到一个新的水平,你可以混合一些 C 预处理器并执行:

#define mPrint(...) Print(__VA_ARGS__, NULL)

Now you can just say:

现在你可以说:

mPrint("fooo","bar");

And the macro will NULLterminate the call.

宏将NULL终止调用。

回答by Alexey Frunze

Instead of passing in the count, you can have a special "trailing" argument (either nullptror a pointer to some hard-coded "magic" string) and your variable-argument functions should stop extracting more arguments once they see the trailing one. That can ease your coding a bit.

您可以有一个特殊的“尾随”参数(或者nullptr指向某个硬编码“魔术”字符串的指针),而不是传入计数,并且您的可变参数函数一旦看到尾随参数就应该停止提取更多参数。这可以稍微简化您的编码。

You could also pass pointers (references) to containers, containing (or pointing at/referencing) your strings. Anything that can somehow link all your individual arguments will do (e.g. a vector).

您还可以将指针(引用)传递给包含(或指向/引用)您的字符串的容器。任何可以以某种方式链接所有个人参数的东西都可以(例如向量)。

Example (might be not very idiomatic, but should serve as an illustration):

示例(可能不是很惯用,但应该作为说明):

#include <iostream>
#include <string>
#include <cstdarg>
#include <cctype>
#include <vector>

using namespace std;

void AntiCapitalize(vector<string*>& v);
void Capitalize(string* s, ...);
void Print(string* s, ...);

int main()
{
    string s1 = "hello";
    string s2 = "world";

    string s3 = "this";
    string s4 = "is";
    string s5 = "a";
    string s6 = "test";

    string s7 = "as";
    string s8 = "many";
    string s9 = "strings";
    string s10 = "as";
    string s11 = "you";
    string s12 = "want";

    Capitalize(&s1, &s2, 0);
    Capitalize(&s3, &s4, &s5, &s6, 0);
    Capitalize(&s7, &s8, &s9, &s10, &s11, &s12, 0);

    Print(&s1, &s2, 0);
    Print(&s3, &s4, &s5, &s6, 0);
    Print(&s7, &s8, &s9, &s10, &s11, &s12, 0);

    vector<string*> v;
    v.push_back(&s1);
    v.push_back(&s2);
    v.push_back(&s3);
    v.push_back(&s4);
    v.push_back(&s5);
    v.push_back(&s6);
    v.push_back(&s7);
    v.push_back(&s8);
    v.push_back(&s9);
    v.push_back(&s10);
    v.push_back(&s11);
    v.push_back(&s12);

    AntiCapitalize(v);

    Print(&s1, &s2, 0);
    Print(&s3, &s4, &s5, &s6, 0);
    Print(&s7, &s8, &s9, &s10, &s11, &s12, 0);

    return 0;
}

void Capitalize(string* s, ...)
{
    va_list ap;

    va_start(ap, s);

    while (s)
    {
        string::size_type i = 0;

        while ((*s)[i] != '
HELLO
WORLD
THIS
IS
A
TEST
AS
MANY
STRINGS
AS
YOU
WANT
hello
world
this
is
a
test
as
many
strings
as
you
want
') { (*s)[i] = toupper((*s)[i]); i++; } s = va_arg(ap, string*); } va_end(ap); } void Print(string* s, ...) { va_list ap; va_start(ap, s); while (s) { cout << *s << endl; s = va_arg(ap, string*); } va_end(ap); } void AntiCapitalize(vector<string*>& v) { vector<string*>::iterator it; for (it = v.begin(); it != v.end(); it++) { string::size_type i = 0; while ((**it)[i] != '
class OutputObject {
public:
    // Some class functions/members

};
template<class T>
static operator << (OutputObject& out, T temp) {
    cout << temp;
}
static OutputObject Obj = OutputObject();
') { (**it)[i] = tolower((**it)[i]); i++; } } }

Output:

输出:

#include "OutputObject.hpp"
#include <string>
using namespace std;
int main(void) {
    string str = "Hello World";
    Obj << 12 << str << 3.14f << "C++";
    Obj << 12;
    Obj << str;
    return(0);
};

回答by Lars

I think there is another possible solution: You could overload an operator '<<' like this:

我认为还有另一种可能的解决方案:您可以像这样重载运算符“<<”:

##代码##

And then you can do the following in the main:

然后您可以在主要内容中执行以下操作:

##代码##

If I did something wrong or there is a reason not to that please tell me, that was just my Idea of infinite parameters. I was not able to test it yet, but I think it should work.

如果我做错了什么或者有理由不这样做,请告诉我,这只是我对无限参数的想法。我还不能测试它,但我认为它应该可以工作。