2016-06-10 7 views
6

Zum BeispielWie implementiert man eine bequeme Initialisierung?

#include <array> 

class Range 
{ 
public: 
    Range(std::array<float, 2> ends) : m_ends(ends) {} 

private: 
    std::array<float, 2> m_ends;  
}; 

und ich kann

Range r({1, 2}); 

Jetzt habe ich eine andere Klasse

class Box 
{ 
public: 
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {} 

private: 
    std::array<Range, 3> m_ranges;  
}; 

Und ich hoffe, dass ich

folgendes tun können
Box b({{1,2}, {3,4}, {5,6}}); 

Aber ich kann nicht. Wie kann ich den Code ändern, um es zu ermöglichen?

+2

Dies funktioniert: 'Box b {{{{{1, 2}}, {{3,4}}, {{5,6}}}}} '. – user1887915

Antwort

4

std::array ist ein bisschen seltsam. Es hat keinen benutzerdefinierten Konstruktor, also ähnelt es einer einfachen Struktur. So std::array<float,2> ist ähnlich wie

struct two_floats { 
    float array[2]; 
}; 

Aus diesem Grund, wenn Sie einen initialisieren, würden Sie tun es logisch wie folgt aus:

two_floats   x = {{1,2}}; 
std::array<float,2> y = {{1,2}}; 

Die äußeren Klammern für die Struktur selbst sind, und die inneren Verstrebungen sind für den Inhalt der Struktur.

kommt es vor, nur zu arbeiten, um einen Satz von Klammern zu bieten:

two_floats x = {1,2}; 

Aber dies ist durch eine spezielle Regel in C++, die Klammern weggelassen werden in bestimmten Fällen erlaubt. Ähnlich wie Sie ein zweidimensionales Array mit nur einem Satz von Klammern initialisieren können:

float x[2][2] = {1,2,3,4}; 

Und das ist, was geschieht, wenn Sie Ihren Bereich wie folgt initialisieren:

Range r({1, 2}); 

das entspricht

std::array<float,2> arg = {1,2}; // one set of braces omittted 
Range r(arg); 

Aber welche mehr explizit geschrieben werden würde, wie:

std::array<float,2> arg = {{1,2}}; 
Range r(arg); 

Eine ähnliche Sache passiert beim Initialisieren der Box. Wenn wir ausdrücklich die Initialisierung schreiben es würde wie folgt aussehen:

std::array<float,2> box_arg1 = {{1,2}}; 
std::array<float,2> box_arg2 = {{3,4}}; 
std::array<float,2> box_arg3 = {{5,6}}; 
std::array<Range,3> box_args = {{box_arg1,box_arg2,box_arg3}}; 
Box b(box_args); 

Also, wenn wir die initializers ersetzen, erhalten wir:

Box b({{{{1,2}},{{3,4}},{{5,6}}}}); 

und das funktioniert. Aber es ist ziemlich hässlich. Diese Initialisierung ist zu komplex, um zuzulassen, dass die zusätzlichen Klammern hier weggelassen werden. Dies ist das Problem, auf das Sie stoßen.

Eine Möglichkeit, um dies zu umgehen, um zusätzliche Konstruktoren zur Verfügung zu stellen, die die einzelnen Array-Elemente übernehmen.

class Range 
{ 
public: 
    Range(float x,float y) : m_ends{x,y} { } 
    Range(std::array<float, 2> ends) : m_ends(ends) {} 

private: 
    std::array<float, 2> m_ends; 
}; 

class Box 
{ 
public: 
    Box(Range x,Range y,Range z) : m_ranges{x,y,z} {} 
    Box(std::array<Range, 3> ranges) : m_ranges(ranges) {} 

private: 
    std::array<Range, 3> m_ranges; 
}; 

Und Sie können jetzt Ihre Box initialisieren wie Sie ursprünglich wollten:

Box b({{1,2}, {3,4}, {5,6}}); 
0

AFAIK nicht mit Array durchgeführt werden kann, müssen Sie Grundtypen zurückgreifen

struct Range 
{ 
    float m_ends[2] ;  
}; 


Range r = {1.0f, 2.0f}; 


struct Box 
{ 
    Range m_ranges[3];  
}; 


Box b = {{{1.0f, 2.0f}, {1.0f, 2.0f}, {1.0f, 2.0f}}}; 
1

Problem

Dieser Code: Box b({{1,2}, {3,4}, {5,6}}); versucht, aggregate initialize Instanzen Range obwohl Range keine ist Aggregat.

Aggregate Initialisierung ist eine Form von list-Initialisierung, die

Aggregate

ein Aggregat ist, eine der folgenden Arten initialisiert:

Array-Typ

Klassentyp (typischerweise struct oder Union), das hat

keine private oder geschützte nicht statische Datenelemente

keine Benutzer bereitgestellten Konstruktoren, einschließlich solche, die aus öffentlichen Basen vererbten (sinceC++ 17) (explizit vorgegeben oder gelöscht Konstruktoren erlaubt)

(da C++ 11) keine virtuelle, private, oder geschützt (da C++ 17) Basis Klassen

keine virtuellen Member-Funktionen

Lösung

Rufen Sie den Konstruktor von Range explicitcly und nur Aggregat initialisieren std::array:

Box b({Range({1,2}), Range({3,4}), Range({5,6})}); 
+1

Es ist kein Aggregat initialize, es versucht zu verwenden [list initialize] (http://en.cppreference.com/w/cpp/language/list_initialization) – user1887915

3

Ich würde nur die Arrays fallen und die üblichen Felder verwenden. Sie können immer eine operator[] Überladung hinzufügen, wenn Sie es wirklich brauchen. Ändern Sie einfach die Feldnamen in das, was Sie gerade modellieren.

class Range 
{ 
public: 
    Range(float x, float y) : m_x{x}, m_y{y} 
    {} 
private: 
    float m_x, m_y; 
}; 

class Box 
{ 
public: 
    Box(Range w, Range h, Range d) : m_w{w}, m_h{h}, m_d{d} 
    {} 
private: 
    Range m_w, m_h, m_d; 
}; 

Live Demo

+0

Der 'operator []' braucht ein 'if' Urteil, Beeinflusst es die Leistung? –

1

Sie könnten vielleicht initializer Listen verwenden:

class Range 
{ 
public: 
    Range(std::initializer_list<float> ends) : m_ends(ends) {} 
    float a() { 
    return m_ends[0]; 
    } 
    float b() { 
    return m_ends[1]; 
    } 

private: 
    std::vector<float> m_ends; 
}; 

class Box 
{ 
public: 
    Box(std::initializer_list<Range> ranges) : m_ranges(ranges) {} 

    void print() 
    { 
    for (auto& i : m_ranges) 
    { 
     std::cout << i.a() << "," << i.b() << std::endl; 
    } 
    } 

private: 
    std::vector<Range> m_ranges; 
}; 


    Range r({ 1,2 }); 
    Box b({ {1,2},{3,4},{5,6} }); 
    b.print(); 

gibt

1,2 
3,4 
5,6 
+0

Sie verwalten nicht die Größe. – Jarod42

+1

@ Jarod42 das ist wahr, zeigt nur einen Pfad –

0

Um eine korrekte initialize Liste, erste Liste seiner vollen Form:

Box b{ 
    array<Range, 3>{{ // std::array needs aggregate-initialize, 
         // and have to initialize a inner array 
         // without a addition '{', C++ is unable to 
         // know that the inner element is Range 
     Range{ 
      {1, 2} // short-hand for array<float>{{3, 4}} 
     }, 
     Range{ 
      {3, 4} 
     }, 
     Range{ 
      {5, 6} 
     } 
    }} 
} 

alle Arten entfernen mit Ausnahme der Box, wir haben:

Box b{ {{ {{1, 2}}, {{3, 4}}, {{5, 6}} }} }