std::tr1::array in Initialisierungliste initialisieren



  • camper schrieb:

    Das einzige, was du mit C++ in der Konstruktorinitialisierungsliste tun erstellen kannst, ist eine Kopie, folglich musst du irgenwie ein Original erstellen, z.B. so:

    typedef std::tr1::array<int, 3> my_array;
    my_array make_array(int a, int b, int c)
    {
        my_array a = { a, b, c };
        return a;
    }
    
    struct foo
    {
        my_array arr;
        foo(int a, int b, int c) : arr( make_array( a, b, c ) ) {}
    ...
    

    Dank Copyelision sollte ein brauchbarer Compiler hierbei keine unnötigen Kopien erstellen.

    Und wie macht man das bei 20 Elementen. 😃



  • camper schrieb:

    Dank Copyelision sollte ein brauchbarer Compiler hierbei keine unnötigen Kopien erstellen.

    Move semantics würde das auch manuell machen.



  • EOutOfResources schrieb:

    Move semantics würde das auch manuell machen.

    move ist ja C++0x, da kann man aber das array direkt in der Initialislierungsliste füllen, ohne Umweg über Copy-Konstruktor.

    hehehe schrieb:

    Und wie macht man das bei 20 Elementen. 😃

    Das schaut nicht anders aus. Aber ob du die 20 Werte direkt in ne Initialisierungsliste schreibst oder als Parameter in ne Funktion packst ist doch wurscht, oder?



  • #include <iostream>
    #include <ostream>
    #include <utility>
    #include <array>
    
    template<class Iter>
    inline void assign_helper(Iter) {}
    
    template<class Iter, class U, class...More>
    inline void assign_helper(Iter it, U&& u, More&&...more)
    {
      *it = std::forward<U>(u);
      ++it;
      assign_helper(it,std::forward<More>(more)...);
    }
    
    template<class T>
    std::array<T,0> make_array() { return std::array<T,0>(); }
    
    template<class T, class U, class...Args>
    std::array<T,1+sizeof...(Args)>
    make_array(U&& u, Args&&...args)
    {
      std::array<T,1+sizeof...(Args)> result;
      assign_helper(&result[0],std::forward<U>(u),std::forward<Args>(args)...);
      return result;
    }
    
    int main()
    {
      using namespace std;
      auto a = make_array<long>(1,2,3,5,8,13,21,34);
      int s = a.size();
      cout << "---" << endl;
      for (int i=0; i<s; ++i) {
        cout << a[i] << '\n';
      }
      cout << "---" << endl;
    }
    

  • Mod

    @krümelkacker: schön nur irgendwie überflüssig. Die Frage stellt sich mit C++0x ja gar nicht erst.



  • Danke für eure Anworten.
    Die Antwort von krümelkacker bietet zwar alles, ist aber recht kompiliziert 🙂
    Wie kann man mit std::move denn ein Array direkt in der Initialisierungsliste füllen?
    Ich hab mir jetzt eine kleine Hilfsfunktion geschrieben, umd ein Array mit einem Wert zu initialisieren:

    template<typename T, size_t size>
    std::array<T, size>&& make_array(T&& t) {
    	std::array<T, size> temp = {t};
    	return std::move(temp);
    };
    

    Jedoch wird hierbei nur das erste Element mit dem Wert t initialisiert. Alle anderen Elemente werden 0. Wie krieg ich das noch hin?



  • Array schrieb:

    template<typename T, size_t size>
    std::array<T, size>&& make_array(T&& t) {
    	std::array<T, size> temp = {t};
    	return std::move(temp);
    };
    

    Jedoch wird hierbei nur das erste Element mit dem Wert t initialisiert. Alle anderen Elemente werden 0. Wie krieg ich das noch hin?

    1. Deine Verwendung von && und std::move ist falsch. Wie kommst Du darauf, der Funktion einen solchen Rückgabetypen zu verpassen? Das interessiert mich mal wirklich. Es gibt nämlich viele, die das falsch machen.

    2. Siehe camper's Beitrag. Ich habe es jetzt nicht extra nachgeguckt, aber nach dem Klang seiner Antwort scheint ein array<>-Objekt sich in C++0x auch im Rahmen der Initialisierungsliste eines Konstruktors ohne weiteres mit Inhalt füllen zu lassen.



  • [quote="EOutOfResources"]Move semantics würde das auch manuell machen./quote]
    Das habe ich versucht.

    Sensai_ schrieb:

    move ist ja C++0x, da kann man aber das array direkt in der Initialislierungsliste füllen, ohne Umweg über Copy-Konstruktor.

    Da habe ich bisher noch nichts zu gefunden.

    krümelkacker schrieb:

    1. Deine Verwendung von && und std::move ist falsch. Wie kommst Du darauf, der Funktion einen solchen Rückgabetypen zu verpassen? Das interessiert mich mal wirklich. Es gibt nämlich viele, die das falsch machen.

    Siehe oben. Ich habe irgendwie versucht mein Halbwissen zu nutzen.
    Wie bekomm ich es denn ohne kopieren richtig hin?



  • krümelkacker schrieb:

    Das interessiert mich mal wirklich. Es gibt nämlich viele, die das falsch machen.

    Hab ich doch letztes Mal zu erklären versucht 🙂

    Nexus schrieb:

    krümelkacker schrieb:

    Rvalue-Referenzen sind REFERENZEN. Punkt. Ich kann mir beim besten Willen nicht erklären, warum so viele, die sich mit Rvalue-Referenzen beschäftigen, auf einmal Funktionen schreiben wollen, die Referenzen auf funktionslokale Objekte zurückgeben, die dann ungültig sind...

    Ich denke, das hängt damit zusammen, dass bisherige bekannte Konstrukte plötzlich eine neue Bedeutung bekommen. Bisher war klar, dass

    MyClass Get();
    

    eine Kopie erzeugt, im besten Fall noch mit (N)RVO wegoptimiert. Dass nun der gleiche Ausdruck ein implizites Move verursachen kann, wenn entsprechende Move-Konstruktoren definiert sind oder compilergeneriert werden, ist halt erst mal neu. Und da Move-Semantik zunächst immer mit RValue-Referenzen in Verbindung gebracht wird, scheint es naheliegend, dass man einen Move mit

    MyClass&& Get();
    

    kennzeichnet.

    Das ist halt das Problem, wenn man grundlegendste und allen bekannte Regeln auf einmal erweitert. Und über die Inkonsistenzen mit Perfect Fowarding und Templates müssen wir gar nicht erst reden, das artet wahrscheinlich eine Massen-Stolperfalle aus.



  • krümelkacker schrieb:

    #include <iostream>
    #include <ostream>
    #include <utility>
    #include <array>
    
    template<class Iter>
    inline void assign_helper(Iter) {}
    
    template<class Iter, class U, class...More>
    inline void assign_helper(Iter it, U&& u, More&&...more)
    {
      *it = std::forward<U>(u);
      ++it;
      assign_helper(it,std::forward<More>(more)...);
    }
    
    template<class T>
    std::array<T,0> make_array() { return std::array<T,0>(); }
    
    template<class T, class U, class...Args>
    std::array<T,1+sizeof...(Args)>
    make_array(U&& u, Args&&...args)
    {
      std::array<T,1+sizeof...(Args)> result;
      assign_helper(&result[0],std::forward<U>(u),std::forward<Args>(args)...);
      return result;
    }
    
    int main()
    {
      using namespace std;
      auto a = make_array<long>(1,2,3,5,8,13,21,34);
      int s = a.size();
      cout << "---" << endl;
      for (int i=0; i<s; ++i) {
        cout << a[i] << '\n';
      }
      cout << "---" << endl;
    }
    

    Sehr elegante Lösung 👍


Anmelden zum Antworten