1

I have a struct called CoolStruct:

struct CoolStruct

{
    int id;
    uint32 type;
    uint32 subtype;
    String name;
};

I have a vector of these structs as well:

std::vector<CoolStruct> coolVector;

I want to create a bunch of structs which have predefined values to push_back into this coolVector. I'd like to keep the code from getting cludgy and ugly. I would really like to keep this notation:

CoolStruct t = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t);
CoolStruct t =  {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t);

But of course this doesn't work... Not allowed to do a reinitialization. Is there any other solution to make this as readable as possible? The only alternative I can think of is it manually set each paramater of the struct:

t.id = whatever; t.type = somethingelse; t.subtype = thisisalotofcode; t.name = justtosetupthisvector;
coolVector.push_back(t);
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Colton Phillips
  • 237
  • 1
  • 4
  • 13
  • 2
    Why not write an appropriate constructor? – Konrad Rudolph Jul 13 '11 at 20:09
  • 1
    @Konrad: That's a lot of boilerplate for absolutely no reason at all if you can get aggregate initialisation working properly. – Lightness Races in Orbit Jul 13 '11 at 20:11
  • Use C++0x, then you can just overwrite the struct with a new one. Aggregates have trivial assignment operators, so that's a breeze once you're allowed to write `t = {a, b, c};`. – Kerrek SB Jul 13 '11 at 20:12
  • 3
    @TomalakGeret'kal I’m all against boilerplate but arguing that a constructor is boilerplate is a tad excessive. *In fact*, i like explicitness; as a consequence, I *always* override the constructor. I also hate that C++ creates a default constructor for me. – Konrad Rudolph Jul 13 '11 at 20:12
  • @Konrad: A constructor that does nothing but initialise members with the same stuff you gave as arguments is completely pointless. Perhaps you'd like to define _several_ constructors, since you clearly like writing out that list of members a lot! – Lightness Races in Orbit Jul 13 '11 at 20:15
  • In C++03, creation of such a constructor results in the struct no longer being POD, which is oftentimes a compelling reason to avoid it without introducing the argument of whether or not the code is overly boilerplate. – Dennis Zickefoose Jul 13 '11 at 20:21
  • Of course, `String` in this case probably precludes `CoolStruct` from POD status anyhow. But you often also have to code a default constructor once you have provided a non-default one, which increases the "boilerplate"-ness of the solution. In the end, a constructor is the right answer to this question, but it is not always the best answer. – Dennis Zickefoose Jul 13 '11 at 20:27
  • @TomalakGeret'kal Granted, the constructor itself is pointless (from a semantic POV). But its presence in the code serves as documentation (remember: self-documenting code) if the class’ desired semantic, and it makes this constraint (= constructible with these parameters) enforceable by the type system. Leaving it off may be OK for small records. It is arguably *never* OK in a public API and personally I strive to meet high coding standards even small, private code snippets. – Konrad Rudolph Jul 13 '11 at 20:30
  • @Konrad: I agree about the API, so fair enough about wanting to maintain that standard. However, I still dispute that adding a constructor here is meeting "high standards"; I'd say that you're making your code worse. – Lightness Races in Orbit Jul 13 '11 at 20:47
  • @Tomalak: Now wait a couple of months until some other developer decides to add a new field to the struct, or profile the code and determine that reordering of two fields can improve cache locality, change the order and see how all the code fails to compile and you have to edit all initializations. Or worse even if the reordering affects two members of compatible types: it compiles perfectly without a glitch, with incorrect values, but who cares about correctness when I managed to pull off not having to write a two line constructor! – David Rodríguez - dribeas Jul 13 '11 at 22:00
  • @David: All good points. – Lightness Races in Orbit Jul 13 '11 at 22:07

2 Answers2

3

how about:

CoolStruct t1 = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t1);
CoolStruct t2 = {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t2);

In C++0x, I think you should be able to do:

CoolStruct t;
t = {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")};
coolVector.push_back(t);
t = {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")};
coolVector.push_back(t);

or even:

coolVector.push_back({1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")});
coolVector.push_back({2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")});

In fact, if you really want to get creative (and you don't have any previous elements that you want to keep), you can replace the whole vector with this syntax:

coolVector = {
   {1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")},
   {2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")}
};
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    or even `coolVector = { { 1, EQData::... }, { 2, EQData::... } };` – Alexandre C. Jul 13 '11 at 20:19
  • I've reinitialized structs by using memset before. Is it because of the String object, you can't? –  Jul 13 '11 at 20:25
  • @0A0D: Quite possibly. Even if not, it's a horrid idea. We left `memset` behind in the 80s, and we use proper language features now. I also don't really see how `memset` helps to solve this problem. You certainly can't "reinitialize" anything. – Lightness Races in Orbit Jul 13 '11 at 20:26
  • @Tomalak: `memset(&struct, 0, sizeof(struct));` will "re-initialize" the struct to 0. –  Jul 13 '11 at 20:32
  • @TomalakGeret'kal let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/1426/discussion-between-0a0d-and-tomalak-geretkal) –  Jul 13 '11 at 20:40
  • @0A0D: You cannot re-initialise anything. You're just overwriting its bits. And your choice of `0` there is completely arbitrary; you could have picked any other integral value. Let's not continue this discussion in chat, because I think it's over. :) – Lightness Races in Orbit Jul 13 '11 at 20:46
  • @Tomalak Your first solution, while not ideal, will work. Your second solution, I\m not using C++0x :P Your third solution, I can't get this to work. I just get syntax errors... Your fourth solution, Can't get to work. Are all of those C++0x solutions? I guess they must be... – Colton Phillips Jul 13 '11 at 20:56
  • @Colton: Either your compiler doesn't support it yet (what version?) or I was wrong about that one. – Lightness Races in Orbit Jul 13 '11 at 20:58
1

if you add a simple constructor:

struct CoolStruct
{
    CoolStruct(int id, uint32 type, uint32 subtype, String name) : id(id), type(type), subtype(subtype), name(name) {}
    int id;
    uint32 type;
    uint32 subtype;
    String name;
};

you can then do this:

CoolVector.push_back(CoolStruct(1, EQData::EQ_EFFECT_TYPE_PARAMETRIC, 0, T("Parametric")));
CoolVector.push_back(CoolStruct(2, EQData::EQ_EFFECT_TYPE_FILTER_LOW_PASS,EQData::EQ_FILTER_TYPE_FILTER_BUTTERWORTH_12DB, T("Low Pass")));
Ferruccio
  • 98,941
  • 38
  • 226
  • 299