I have a very big class with a bunch of members, and I want to initialize them with a given specific value.The code below is the most naive implementation, but I don't like it since it's inelegant and hard to maintain because I have to list all the members in the constructor.
struct I_Dont_Like_This_Approach {
int foo;
long bar;
unsigned baz;
int a;
int b;
int c;
int d;
SomeStruct and_so_on;
/*...*/
public:
explicit I_Dont_Like_This_Approach(int i) : foo(i), bar(i), baz(i), a(i), b(i), c(i), d(i), and_so_on(i) /*...*/ {}
};
I thought of an alternative implementation using templates.
template <int N>
struct MyBigClass {
int foo{N};
long bar{N};
unsigned baz{N};
int a{N};
int b{N};
int c{N};
int d{N};
SomeStruct and_so_on{N};
/*...*/
};
but I'm not sure if the code below is safe.
MyBigClass<1> all_one;
MyBigClass<2> all_two;
/* Is the following reinterpret_cast safe? */
all_one = reinterpret_cast<decltype(all_one) &>(all_two);
Does the C specification have any guarantees about the data layout compatibility of such templated structs? Or is there a more reasonable implementation? (in standard C , and don't use macros)
CodePudding user response:
I would argue that the first one is much more maintainable, with the right warnings enabled (and a modern compiler), you will see if your initializer list gets out of sync with the class fields at compile time.
As to your alternative.. you're using templates as compiler arguments, which is not what they're meant to be. That brings a whole slew of issues:
- instantiated templates get copied in memory, making your executable larger. Though in this case, I'm hoping your compiler is smart enough to see that the field structure is the same and treat it as one type.
- your code now works only with constant literal integers, no more run-time variables.
- there is indeed no guarantee that the memory structure of those two classes is the same. You can disable optimizations in most compilers (like pack, alignment, etc), but that comes at the cost of disabling optimizations, which isn't actually necessary except to support your specific code.
And related to the last one, if you ever need to consider whether this is ever going to break, you're heading down a very dark road. I mean any sane person can tell you it will "probably work", but the fact that you have no guarantees in the language that pretty much popularized memory corruption and buffer overflows should terrify you. Write constructors.