[C++] Comoda inizializzazione della struct in C ++


Answers

La tua domanda è alquanto difficile perché anche la funzione:

static FooBar MakeFooBar(int foo, float bar);

può essere chiamato come:

FooBar fb = MakeFooBar(3.4, 5);

a causa delle regole di promozione e conversione per i tipi numerici incorporati. (C non è mai stato veramente fortemente tipizzato)

In C ++, ciò che si desidera è ottenibile, anche se con l'aiuto di modelli e asserzioni statiche:

template <typename Integer, typename Real>
FooBar MakeFooBar(Integer foo, Real bar) {
  static_assert(std::is_same<Integer, int>::value, "foo should be of type int");
  static_assert(std::is_same<Real, float>::value, "bar should be of type float");
  return { foo, bar };
}

In C, puoi nominare i parametri, ma non potrai mai andare oltre.

D'altra parte, se tutto ciò che si desidera è denominato parametri, allora si scrive un codice molto ingombrante:

struct FooBarMaker {
  FooBarMaker(int f): _f(f) {}
  FooBar Bar(float b) const { return FooBar(_f, b); }
  int _f;
};

static FooBarMaker Foo(int f) { return FooBarMaker(f); }

// Usage
FooBar fb = Foo(5).Bar(3.4);

E se vuoi, puoi dare un po 'di protezione alla promozione del tipo.

Question

Sto cercando di trovare un modo conveniente per inizializzare le strutture C ++ di "pod". Ora, considera la seguente struttura:

struct FooBar {
  int foo;
  float bar;
};
// just to make all examples work in C and C++:
typedef struct FooBar FooBar;

Se voglio inizializzare opportunamente questo in C (!), Potrei semplicemente scrivere:

/* A */ FooBar fb = { .foo = 12, .bar = 3.4 }; // illegal C++, legal C

Nota che voglio evitare esplicitamente la seguente notazione, perché mi sembra che mi facciano rompere il collo se cambio qualcosa nella struttura in futuro:

/* B */ FooBar fb = { 12, 3.4 }; // legal C++, legal C, bad style?

Per ottenere lo stesso (o almeno simile) in C ++ come nell'esempio /* A */ , dovrei implementare un costruttore idiota:

FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar) {}
// ->
/* C */ FooBar fb(12, 3.4);

Che è buono per l'acqua bollente, ma non adatto per i pigri (la pigrizia è una buona cosa, giusto?). Inoltre, è tanto male quanto l'esempio /* B */ , in quanto non indica esplicitamente quale valore va a quale membro.

Quindi, la mia domanda è fondamentalmente come posso ottenere qualcosa di simile a /* A */ o meglio in C ++? In alternativa, sarei a posto con una spiegazione del perché non dovrei volerlo fare (cioè perché il mio paradigma mentale è cattivo).

MODIFICARE

Con comodo , intendo anche mantenibile e non ridondante .




Estrarre i contant nelle funzioni che li descrivono (refactoring di base):

FooBar fb = { foo(), bar() };

So che lo stile è molto vicino a quello che non volevi usare, ma consente una più facile sostituzione dei valori costanti e anche spiegarli (quindi non è necessario modificare i commenti), se mai lo cambiano.

Un'altra cosa che potresti fare (dato che sei pigro) è rendere il costruttore in linea, quindi non devi digitare tanto (rimuovere "Foobar ::" e passare il tempo tra il file h e cpp):

struct FooBar {
  FooBar(int f, float b) : foo(f), bar(b) {}
  int foo;
  float bar;
};



E 'ancora un altro modo in C ++

struct Point
{
private:

 int x;
 int y;

public:
    Point& setX(int xIn) { x = Xin; return *this;}
    Point& setY(int yIn) { y = Yin; return *this;}

}

Point pt;
pt.setX(20).setY(20);



Il modo in cui /* B */ va bene in C ++, anche il C ++ 0x estenderà la sintassi, quindi è utile anche per i contenitori C ++. Non capisco perché lo chiami brutto stile?

Se si desidera indicare i parametri con i nomi, è possibile utilizzare la libreria dei parametri boost , ma potrebbe confondere qualcuno che non ha familiarità con esso.

Riordinare i membri della struttura è come riordinare i parametri delle funzioni, tale refactoring può causare problemi se non lo si fa con molta attenzione.