Let's say I have the following structure:
template <typename T>
struct Wrapper {
virtual T* get() const = 0;
protected:
void *c_;
};
template <typename C, typename T>
struct WrapperOf: Wrapper<T> {
WrapperOf(C *c = 0) : c_(c) { }
virtual T* get() const {
C *c = static_cast<C*>(c_);
return static_cast<T*>(c->get());
}
};
Is it guaranteed by the standard that the size of any WrapperOf
will be the same? Typically, could I do the following:
struct Dummy { void* get(); };
struct Real { int* get(); };
char storage[sizeof(WrapperOf<Dummy, void>)];
Wrapper<int> *wp =
new(storage) WrapperOf<Real, int>();
And if I specialize WrapperOf
, typically:
template <>
struct WrapperOf<void, void>: Wrapper<void> {
virtual void* get() const { return 0; }
};
To use it to initialize the storage (to avoid having a Dummy
class):
char storage[sizeof(WrapperOf<void, void>)];
Would this still be valid?
From the current working draft N4640 (2017-02-06)
5.3.3 Sizeof [expr.sizeof]
The sizeof operator yields the number of bytes in the object representation of its operand.
... When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.
So there's no guaranty about anything, just that it takes so much bytes as it takes.
Even for most fundamental types, the standard says it is implementation-defined
- ... sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1. The result of sizeof applied to any other fundamental type (3.9.1) is implementation-defined.
One can infer that it takes N bytes for some class and empirically see that it is the same for a range of derived classes in a given implementation. There is just no guaranty.