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

How do I write functions that accept unlimited arguments?

本文关键字:参数 函数 无限 何编写      更新时间:2023-10-16

我只能为函数找到一种方法来获取可变数量的参数
是这样的:

#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个问题:
1.)我必须指定要发送多少个参数-这是不可取的
2.)我不知道如何修改它,所以它会输出字符串。

这样的事情是否可能在不必多次过载功能的情况下实现:

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
}

这个怎么样:

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
}

我所能想到的就是:
-多次重载函数
-具有接受某种类型的容器而不是的功能

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

使用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;
}

快速简单的答案。

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

你的第一个例子是指定计数的一个很好的例子,你也可以这样做:

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

您的呼叫约定在哪里:

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

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

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

现在你可以说:

mPrint("fooo","bar");

并且宏将NULL终止调用。

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

您还可以向容器传递指针(引用),其中包含(或指向/引用)您的字符串。任何能以某种方式将你所有的个人论点联系起来的东西都可以(例如向量)。

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

#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] != '')
        {
            (*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] != '')
        {
            (**it)[i] = tolower((**it)[i]);
            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

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

class OutputObject {
public:
    // Some class functions/members
};
template<class T>
static operator << (OutputObject& out, T temp) {
    cout << temp;
}
static OutputObject Obj = OutputObject();

然后你可以主要做以下事情:

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

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