arrays überladen



  • Mein Vorschlag fuer make_array:

    template <typename Head, typename... Tail>
    std::array<Head, 1+sizeof...(Tail)> make_array(Head&& head, Tail&&... tail) {
        return std::array<Head, 1+sizeof...(Tail)> { std::forward<Head>(head), std::forward<Tail>(tail)... };
    }
    

    Verbesserungsvorschlaege willkommen
    Bin mit den neuen features noch nicht so per du 😉



  • Funktioniert mit Clang 3.0:

    #include <array>
    
    template <class First, class ...Rest>
    auto make_array(First && first, Rest && ...rest)
    	-> std::array<First, 1 + sizeof...(Rest)>
    {
    	return
    	{
    		std::forward<First>(first),
    		std::forward<Rest>(rest)...
    	};
    }
    
    int main()
    {
    	const auto a = make_array(1, 2, 3, 4);
    	static_assert(std::is_same<const std::array<int, 4>, decltype(a)>::value,
    		"make_array liefert einen unerwarteten Typ");
    }
    

    Ist das korrekt und optimal so?



  • Shade Of Mine schrieb:

    Ethon schrieb:

    Da sowohl normale Arrays als auch std::array eine konstante Größe erfordern, ist es total egal wie gut man im Code die Größe bestimmen kann, da sie sowieso bekannt sein muss.

    Das ist aber leider nicht gegeben. Sobald ich das Array naemlich an eine Funktion uebergebe verliere ich idR diese Information. Ich kann natuerlich immer aufpassen die korrekte Groesse immer mitzugeben - aber bei std::array ist sie immer da egal was passiert.

    std::array ist in jeder einzelnen Situation besser (bzw. gleich gut) als ein plain array. Jeder einzelnen.

    Nö, bei std::array musst du die Information doch auch explizit mitgeben.

    template<std::size_t Size>
    void i_like_ints(std::array<int, Size>& ints) {}
    


  • Ethon schrieb:

    Nö, bei std::array musst du die Information doch auch explizit mitgeben.

    Bei einem plain array musst du das nicht. 💡



  • Ethon schrieb:

    template<std::size_t Size>
    void i_like_ints(std::array<int, Size>& ints) {}
    

    Keine Ahnung warum man so ein template haben will, aber bitte - funktioniert einwandfrei:

    auto a=make_array(1,2,3,4,5);
    i_like_ints(a);
    

  • Mod

    Shade Of Mine schrieb:

    aber folgendes nicht?

    template <typename Head, typename... Tail>
    std::array<Head,1+sizeof...(Tail)> make_array(Head head, Tail const&... tail) {
        return std::array<Head,1+sizeof...(Tail)> ({ head, tail... });
    }
    

    Weil hierfür ein list-Konstruktor erforderlich wäre.


  • Mod

    Mein Vorschlag

    template <typename... Args>
    constexpr std::array<typename std::common_type<typename std::decay<Args>::type...>::type, sizeof...(Args)> make_array(Args&&... args)
    {
        return { std::forward<Args>( args )... };
    }
    

    evtl. noch eine Prüfung, dass kein narrowing stattfindet.



  • camper schrieb:

    Weil hierfür ein list-Konstruktor erforderlich wäre.

    Gibt es einen Grund warum es so einen ctor nicht gibt?
    Klar kann man nicht statisch ueberpruefen dass die elementanzahl passt - aber das waere per assert ja auch ok...


  • Mod

    Shade Of Mine schrieb:

    Gibt es einen Grund warum es so einen ctor nicht gibt?

    Weil array ein Aggregat sein soll. Wenn es keins wäre und ein List-Konstruktor existierte, hätte man u.a. auch das Problem, dass Narrowing verboten wäre; da array nichts Neues ist, hätte man dann auch mit zusätzlichen Inkompatibilitäten gegenüber C++03 zu kämpfen.



  • camper schrieb:

    Shade Of Mine schrieb:

    Gibt es einen Grund warum es so einen ctor nicht gibt?

    Weil array ein Aggregat sein soll.

    oh, ok.
    macht natuerlich sinn.


  • Mod

    Shade Of Mine schrieb:

    camper schrieb:

    Shade Of Mine schrieb:

    Gibt es einen Grund warum es so einen ctor nicht gibt?

    Weil array ein Aggregat sein soll.

    oh, ok.
    macht natuerlich sinn.

    Wenn man weiter denkt, eigentlich nicht.
    array ist ja deshalb als Aggregat eingeführt worden, damit diese Art Initialisierung (auch in C++03) durchgeführt werden kann. Jetzt wäre das an sich nicht mehr erforderlich. Und weil es unterspezifiziert ist, kann man std::array nicht felxibel einsetzen, wenn man portabel bleiben will: es wird nämlich nicht gesagt, wie die vollständige Klammerung auszusehen hat, sondern nur, dass

    array<T, N> a = { initializer-list };
    

    funktionieren soll. Dabei findet allerdings mit Sicherheit brace-elision statt, und gerade die ist ja in anderen Kontexten (z.B. Member-Initialisierer) nicht zulässig.
    Nur steht eben nirgendwo, dass

    array<T, N> a = {{ initializer-list }};
    

    a) möglich und b) die vollstäng geklammerte Variante ist.

    Beispielsweise könnte array ja so aussehen

    template <typename T, size_t N>
    struct array {
    ...
        T elems[1][1][1][N];
    };
    

    unsinnig, aber möglich.


Anmelden zum Antworten