Вложенные шаблонные классы

78
10

Я хочу иметь возможность создать общий вложенный шаблон, чтобы я мог найти общий размер всех классов. Для начала, представьте для классов A, B, C, и т.д.... каждый из которых имеет mSize элемент, и GetSize() функции. Я выполняю следующий процесс:

int main()
{
using Abc = A<B<C<>>>; // Imagine it is defined similarly to this for now.
Abc abc;

std::cout << abc.GetSize() << std::endl;

// For abc.GetSize(), this will do the following:
// 1. Go into A::GetSize().
// 2. This will return A::mSize + B::GetSize()
// 3. This will go into B::GetSize()
// 4. This will return B::mSize + C::GetSize()
// 5. Etc
// Overall, we will have the total size of A+B+C as
// A::mSize + B::mSize + C::mSize.

return 0;
}

Он будет рекурсивно проходить каждый класс шаблона до конца и вызвать GetSize(). Мои текущие попытки сделать это были с использованием шаблонов-шаблонов и вариативных шаблонов.

template <template<typename> class First, template<typename> class ...Args>
class A
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{1};
};

template <template<typename> class First, template<typename> class ...Args>
class B
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{2};
};

template <template<typename> class First, template<typename> class ...Args>
class C
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{3};
};

Очевидно, это не сработало. Мне бы очень хотелось получить способ, описанный в int main().

Примечания:

Эти классы необязательно должны быть включены или быть в порядке. Мы могли бы иметь A<C> или B<E<C<F<>>>>. В идеале это может быть бесконечно долго.

Я не хочу использовать полиморфизм, желая, чтобы он был разрешен во время выполнения. Я мог бы наследовать все из одного класса, создать std::vector<Parent*>, push_back каждый дочерний класс и выполнить итерацию с помощью GetSize(). Было бы неплохо определить уникальные типы, такие как A<B<>>, A<B<C<>>> и т.д.

спросил(а) 2021-01-25T11:01:07+03:00 4 месяца, 4 недели назад
1
Решение
100

Поскольку ваш mSize одинаковый для всех экземпляров, ваш метод должен быть static, и поскольку он выглядит как константа, он должен быть constexpr.

Вот реализация, которая использует общий шаблон, а затем частично создает экземпляр с конкретными размерами:

template <int Size, typename T>
struct Holder {
static constexpr int GetSize() {
return Size + T::GetSize();
}
};

template <int Size>
struct Holder<Size, void> {
static constexpr int GetSize() {
return Size;
}
};

template <typename T = void>
using A = Holder<1, T>;

template <typename T = void>
using B = Holder<2, T>;

template <typename T = void>
using C = Holder<3, T>;

Затем вы можете проверить:

using AB = A<B<>>;
using ABC = A<B<C<>>>;

static_assert(AB::GetSize() == 1 + 2, "Oops!");
static_assert(ABC::GetSize() == 1 + 2 + 3, "Oops!");

Конечно, вы можете сделать A, B, C ,... extends Holder а не частично создавать его, если вам это нужно.

ответил(а) 2021-01-25T11:01:07+03:00 4 месяца, 4 недели назад
88

Вы могли бы сделать что-то вроде:

#include <iostream>
#include <type_traits>

using namespace std;

template <class T>
struct A {
static constexpr int size = 1;
using inner_type = T;
};

template <class T>
struct B {
static constexpr int size = 2;
using inner_type = T;
};

//template <class T>
struct C {
static constexpr int size = 3;
using inner_type = void;
};

template <class T, class = void>
struct TotalSizeGetter {
static constexpr int get() {
return T::size + TotalSizeGetter<typename T::inner_type>::get();
}
};

template <class T>
struct TotalSizeGetter<T, typename enable_if<is_void<typename T::inner_type>::value>::type> {
static constexpr int get() {
return T::size;
}
};

int main() {
cout << TotalSizeGetter<A<B<C>>>::get() << endl;
}

Это использует С++ 11 constexpr и enable_if но я вижу, что это не ограничение, так как вы используете термин вариативные шаблоны в вашем вопросе...

ответил(а) 2021-01-25T11:01:07+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема