Начните с типа словаря:
template<class T>
struct span {
T* b = nullptr;
T* e = nullptr;
// these all do something reasonable:
span()=default;
span(span const&)=default;
span& operator=(span const&)=default;
// pair of pointers, or pointer and length:
span( T* s, T* f ):b(s), e(f) {}
span( T* s, size_t l ):span(s, s+l) {}
// construct from an array of known length:
template<size_t N>
span( T(&arr)[N] ):span(arr, N) {}
// Pointers are iterators:
T* begin() const { return b; }
T* end() const { return e; }
// extended container-like utility functions:
T* data() const { return begin(); }
size_t size() const { return end()-begin(); }
bool empty() const { return size()==0; }
T& front() const { return *begin(); }
T& back() const { return *(end()-1); }
};
// This is just here for the other array ctor,
// a span of const int can be constructed from
// an array of non-const int.
template<class T>
struct span<T const> {
T const* b = nullptr;
T const* e = nullptr;
span( T const* s, T const* f ):b(s), e(f) {}
span( T const* s, size_t l ):span(s, s+l) {}
template<size_t N>
span( T const(&arr)[N] ):span(arr, N) {}
template<size_t N>
span( T(&arr)[N] ):span(arr, N) {}
T const* begin() const { return b; }
T const* end() const { return e; }
size_t size() const { return end()-begin(); }
bool empty() const { return size()==0; }
T const& front() const { return *begin(); }
T const& back() const { return *(end()-1); }
};
этот тип был введен в C ++ std
(с небольшими отличиями) через GSL.Приведенного выше базового типа словаря достаточно, если у вас его еще нет.
Диапазон представляет «указатель» на блок смежных объектов известной длины.
Теперь мы можем поговорить оa span<char>
:
class Base
{
public:
void iterateInfo()
{
for(const auto& info : c_mySpan) {
DPRINTF("Name: %s - Value: %f \n", info.name, info.value);
}
}
private:
span<const char> c_mySpan;
Base( span<const char> s ):c_mySpan(s) {}
Base(Base const&)=delete; // probably unsafe
};
Теперь ваш производный выглядит следующим образом:
class DerivedA : public Base
{
public:
const SomeInfo c_myInfo[2] { {"NameA1", 1.1f}, {"NameA2", 1.2f} };
DerivedA() : Base(c_myInfo) {}
};
Это накладные расходы в два указателя на Base
.Vtable использует один указатель, делает ваш тип абстрактным, добавляет косвенность и добавляет один глобальный vtable для каждого типа Derived
.
Теперь, теоретически, вы можете сократить издержки на длину массиваи предположим, что данные массива начинаются сразу после Base
, но это хрупко, непереносимо и полезно только в отчаянном состоянии.
Хотя вы можете быть совершенно осторожны с шаблонами во встроенном коде (как и должно быть)любого типа генерации кода; генерация кода означает, что вы можете сгенерировать более O (1) двоичного кода из O (1) кода).Тип словаря span является компактным и не должен указывать ни на что, если настройки компилятора достаточно агрессивны.