Как найти максимально возможный размер дочернего класса - PullRequest
1 голос
/ 08 июня 2019

Учитывая класс, я хотел бы найти самый большой sizeof() всех его дочерних классов во время компиляции. В этом случае вам нужно будет правильно определить значение B::BIGGEST_TYPE_SIZE, предпочтительно в самом классе.

Можно сделать это в отдельном фрагменте кода с использованием std::max(), как показано в последней строке, но это несколько дублирует код и делает его не элегантным, так как мне придется постоянно изменять эту строку по мере увеличения числа классов. наследовать от B.

Вместо этого я хотел бы получить хорошее масштабируемое решение.

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)));

Значение BIGGEST_TYPE_SIZE должно быть "32" из-за std::string.

Какие-нибудь элегантные решения для этого? Чем сексуальнее шаблоны, тем лучше. Спасибо!

Ответы [ 2 ]

2 голосов
/ 08 июня 2019

Взять, к примеру, std::variant, он знает его размер из аргументов шаблона. Ваш лучший снимок - это также использовать шаблон с переменным углом. Сначала вы реализуете шаблон * variadic max функции , а затем используете его:

template <typename ... Ts>
constexpr bool biggest_size_v = max(sizeof(Ts)...);

Если вы хотите автоматически получить список всех производных классов во время компиляции. Ты не можешь Вы все еще должны перечислить их:

const int B::BIGGEST_TYPE_SIZE = biggest_size_v<D1, D2, D3>;
1 голос
/ 08 июня 2019

Это можно сделать отдельным фрагментом кода с использованием std :: max, как показано в последней строке, но это несколько дублирует код и делает его не элегантным, поскольку мне придется постоянно его модифицировать.строка, поскольку все классы наследуются от B.

Вместо этого я хотел бы получить хорошее масштабируемое решение.

К сожалению, я не знаю способа автоматически узнать все производные типы (я нене думаю, что это возможно) поэтому я боюсь, что вам нужно «постоянно изменять эту строку, так как все больше классов наследуют форму B».

В ответе LogicStuff вы видите элегантный способ упростить эту строку, и я также помню,существуют версия std::max(), которая получает std::initializer_list (constexpr начиная с C ++ 14), поэтому вы также можете писать (но способ biggest_size_v лучше, ИМХО)

const int B::BIGGEST_TYPE_SIZE
   = std::max({sizeof(D1), sizeof(D2), sizeof(D3)});

избегая множественных вызовов std::max().

Я полагаю, что это немного не по теме, но я предлагаю вам полуавтоматический способ проверки во время компиляции, что B::BIGGEST_TYPE_SIZE больше (или равно) дляsizeof() всех производных типов (всеинстанцированный производный тип, как минимум).

Если вы измените B, добавив конструктор с static_assert() в нем (или, если хотите, SFINAE)

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, "!" ); }
 };

и добавьтешаблон C struct, который наследуется от B

template <typename Der>
struct C : public B
 {
   C() : B{std::integral_constant<std::size_t, sizeof(Der)>{}}
    { }
 };

, если вы изменяете ваши Dx классы для наследования B, проходящего через C<Dx> (таким образом, используя 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; };

вы автоматически включаете проверку во время компиляции внутри B конструктора.

Поэтому, если вы добавите, например, следующий D4 класс

struct D4 : public C<D4>
 { int a[42]; };

и забудетеЧтобы изменить инициализацию BIGGEST_TYPE_SIZE, добавив в список sizeof(D4), объявив объект D4, вы получите ошибку компиляции

D4 d4; // compilation error

Ниже приведен полный пример компиляции

#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
 }
...