Reputation: 25
Given a class, I would like to find the largest sizeof()
all child classes of it in compile-time. In this case, you will need to properly define the value of B::BIGGEST_TYPE_SIZE
, preferably in the class itself.
It is possible to do so in a separate chunk of code with the usage of std::max()
as shown in the last line, but it's some what duplicate code and unelegant, as I will have to continuously modify that line as more classes inherit from B
.
I would like a nice scalable solution instead.
struct B
{
static const int BIGGEST_TYPE_SIZE;
};
struct D1 : public B
{
int i;
};
struct D2 : public B
{
std::vector<int> vec;
};
struct D3 : public B
{
std::string s;
};
const int B::BIGGEST_TYPE_SIZE = std::max(sizeof(D1), std::max(sizeof(D2), sizeof(D3)));
The value of BIGGEST_TYPE_SIZE
should be "32", due to std::string
.
Any elegant solutions for this? The sexier the templates, the better. Thanks!
Upvotes: 1
Views: 281
Reputation: 66200
It is possible to do so in a separate chunk of code with the usage of std::max as shown in the last line, but it's some what duplicate code and unelegant, as I will have to continuously modify that line as more classes inherit from B.
I would like a nice scalable solution instead.
Unfortunately, I don't know a way to automatically know all derived types (I don't think it's possible) so I fear that you needs "to continuously modify that line as more classes inherit form B
".
In LogicStuff's answer you see an elegant way to simplify that line and I also remember that exist the std::max()
version that receive a std::initializer_list
(constexpr
starting from C++14) so you can also write (but the biggest_size_v
way is better, IMHO)
const int B::BIGGEST_TYPE_SIZE
= std::max({sizeof(D1), sizeof(D2), sizeof(D3)});
avoiding the multiple std::max()
calls.
A little off topic, I suppose, but I propose you a semi-automatic way to check, compile-time, that B::BIGGEST_TYPE_SIZE
is bigger (or equal) to the sizeof()
of all derived types (all instantiated derived type, at least).
If you modify B
adding a constructor with a static_assert()
in it (or SFINAE enabled, if you prefer)
struct B
{
static const int BIGGEST_TYPE_SIZE;
template <std::size_t DerSize>
B (std::integral_constant<std::size_t, DerSize>)
{ static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
};
and add a template C
struct that inherit from B
template <typename Der>
struct C : public B
{
C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
{ }
};
if you modify your Dx
classes to inheriting B
passing through C<Dx>
(so using CRTP)
struct D1 : public C<D1>
{ int i; };
struct D2 : public C<D2>
{ std::vector<int> vec; };
struct D3 : public C<D3>
{ std::string s; };
you auto-magically enable the compile-time check inside B
constructor.
So if you add, by example, the following D4
class
struct D4 : public C<D4>
{ int a[42]; };
and forget to modify the BIGGEST_TYPE_SIZE
initialization adding sizeof(D4)
in the list, declaring a D4
object you get a compilation error
D4 d4; // compilation error
The following is a full compiling example
#include <vector>
#include <iostream>
#include <algorithm>
struct B
{
static const int BIGGEST_TYPE_SIZE;
template <std::size_t DerSize>
B (std::integral_constant<std::size_t, DerSize>)
{ static_assert( DerSize <= BIGGEST_TYPE_SIZE, "!" ); }
};
template <typename Der>
struct C : public B
{
C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
{ }
};
struct D1 : public C<D1>
{ int i; };
struct D2 : public C<D2>
{ std::vector<int> vec; };
struct D3 : public C<D3>
{ std::string s; };
struct D4 : public C<D4>
{ int a[42]; };
const int B::BIGGEST_TYPE_SIZE
= std::max({sizeof(D1), sizeof(D2), sizeof(D3)}); // <-- sizeof(D4) forgotten !!!
int main ()
{
D1 d1;
D2 d2;
D3 d3;
// D4 d4; compilation error
}
Upvotes: 1
Reputation: 19607
Take for example std::variant
, it knows its size from the template arguments. Your best shot is also to use a variadic template. First, you implement the variadic max
function template, then you use it:
template <typename ... Ts>
constexpr bool biggest_size_v = max(sizeof(Ts)...);
If you're asking to automatically get a list of all derived classes at compile-time. You can't. You still have to list them:
const int B::BIGGEST_TYPE_SIZE = biggest_size_v<D1, D2, D3>;
Upvotes: 2