Как написать функции, которые принимают неограниченные аргументы?
Мне удалось найти способ один, чтобы функции принимали переменное количество аргументов.
Это так:
#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
}
Все, что я могу сделать, это:
-обновлять функцию несколько раз
-функция принимает некоторый тип контейнера вместо
Если это НЕ ВОЗМОЖНО, может кто-нибудь объяснить, почему компилятор не способен выполнить такую задачу.
Ответы
Ответ 1
С переменными шаблонами в С++ 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;
}
Ответ 2
Быстрый и простой ответ.
Для С++ вам нужно указать либо количество аргументов, либо значение дозорного, чтобы указать конец аргументов.
Ваш первый пример - хороший пример использования count, вы также можете сделать:
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
завершает вызов.
Ответ 3
Вместо того, чтобы передавать счет, у вас может быть специальный "конечный" аргумент (либо 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] != '\0')
{
(*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] != '\0')
{
(**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
Ответ 4
Я думаю, что есть еще одно возможное решение:
Вы можете перегрузить оператор '< < например:
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);
};
Если я сделал что-то не так, или есть причина не для этого, пожалуйста
скажи мне, что это была моя идея бесконечных параметров.
Я еще не смог проверить его, но я думаю, что он должен работать.