Funktionen: beliebig viele Parameter



  • Guten Abend,
    ich möchte meine Funktion mit beliebig vielen Parametern schreiben. im Prinzip funktioniert das auch so. (Kein Compilerfehler)

    void writevector(const vector <double> x, char y[]=NULL...){
    	cout<<"[ ";
    	for(int i=0;i<x.size();i++){
    		cout<<x[i];
    		if(i<x.size()-1) cout<<", ";
    
    	}
    	cout<<"]";
    	if(y!=NULL){
    		for(int i=0;y[i]!='\0';i++)
    			cout<<y[i];
    	}
    }
    

    Wenn ich die Funktion nun mit

    writevector(x,"klappt","klapptnicht");
    

    aufrufe, werden leider nur die ersten beiden Parameter ausgegeben, der dritte nicht mehr. Wie kann ich das realisieren, dass alle ausgegeben werden?

    Viele Grüße



  • Nicht so einfach.

    void writevector(const vector <double> x, char y[]=NULL...);
    

    ist äquivalent zu

    void writevector(const vector <double> x, char y[]=NULL, ...);
    

    Das ist eine selten benutzte syntaktische Besonderheit. Dementsprechend lässt sich das wie in jeder andere variadische Funktion behandeln - du musst halt nur auf irgendeine Weise bekannt machen, wann deine Parameterliste zu Ende ist. In der Regel gibt man entweder vorn die Anzahl der Parameter an oder setzt einen Terminator (üblicherweise NULL). Beispiel:

    #include <algorithm>
    #include <cstdarg>
    #include <cstddef>
    #include <iostream>
    #include <iterator>
    #include <vector>
    
    void foo(std::vector<double> const &x, ...) {
      va_list vl;
    
      std::cout << "[ ";
      if(!x.empty()) {
        std::copy(x.begin(),
                  x.end  () - 1,
                  std::ostream_iterator<double>(std::cout, ", "));
        std::cout << x.back();
      }
      std::cout << " ]";
    
      char const *str;
      va_start(vl, x);
      while(str = va_arg(vl, char const *)) {
        std::cout << str;
      }
      va_end(vl);
    
      std::cout << std::endl;
    }
    
    int main() {
      std::vector<double> x;
    
      x.push_back(1);
      x.push_back(2);
    
      foo(x, "bar", "baz", static_cast<char const *>(0));
    }
    

    bzw.

    #include <algorithm>
    #include <cstdarg>
    #include <cstddef>
    #include <iostream>
    #include <iterator>
    #include <vector>
    
    void foo(std::vector<double> const &x, std::size_t n, ...) {
      va_list vl;
    
      std::cout << "[ ";
      if(!x.empty()) {
        std::copy(x.begin(),
                  x.end  () - 1,
                  std::ostream_iterator<double>(std::cout, ", "));
        std::cout << x.back();
      }
      std::cout << " ]";
    
      va_start(vl, n);
      for(std::size_t i = 0; i < n; ++i) {
        std::cout << va_arg(vl, char const *);
      }
      va_end(vl);
    
      std::cout << std::endl;
    }
    
    int main() {
      std::vector<double> x;
    
      x.push_back(1);
      x.push_back(2);
    
      foo(x, 2, "bar", "baz");
    }
    

    Wenn dein Präprozessor variadische Makros beherrscht, kann man da mit Makros syntaktischen Zucker draufgießen. Das sähe dann etwa so aus:

    void foo_impl(std::vector<double> const &x, ...);
    #define foo(x, ...) foo_impl(x, __VA_ARGS__, static_cast<char const *>(0))
    

    Es hat allerdings die üblichen Nachteile im Umgang mit Makros.

    Mit C++11 und variadischen Templates wird man das besser (d.h. typsicher) drehen können.



  • cool danke!

    aber da muss ich doch gleich mal fragen, warum c++ nciht die ausgabe von vectoren von haus aus unterstützt, wie es andere sprachen auch tun.

    // x sei ein vector
    cout<<x;
    

    vectoren und cout sind doch beides standardisierte sprachbausteine...



  • Das musst du das Standardisierungskomitee fragen. Ich gebe allerdings zu bedenken, dass es ungefähr 20 Quadrilliarden verschiedene Möglichkeiten gibt, einen Container bei der Ausgabe zu formatieren und die Funktionalität trivial zu implementieren ist. Die Sinnhaftigkeit eines standardisierten Ausgabeoperators (und symmetrischen Eingabeoperators) scheint mir zweifelhaft.


  • Mod

    Statt Funktionen beliebig viele Argumente zu verpassen, ist es eine Überlegung wert, ob man es wie die Streams machen kann. Das heißt ein Funktionsobjekt, welches nach und nach mit Argumenten gefüttert wird und erst bei einem bestimmten Argument (flush/endl) loslegt.


Log in to reply