Дорогие форумчане, здравствуйте!
В соседней ветке по плюсам развернулась дискуссия о том, зачем нужны шаблоны.
Да вот хотя бы для этого — нужно решить задачу на современных плюсах(С++14, С++17) с использованием шаблонов.
В решение данной задачи помогла в т.ч.
книгаАвтор: LaptevVV
Дата: 21.05.18
, описанная Валерием Лаптевым.
Три года назад я начал изучать программирование по его книги "C++. Экспресс курс".
Тогда для меня задача по вычислению дня рождения в зависимости от високосности года было верхом программисткой мысли.
Сейчас пошли уже такие "игрушки"
Выложу:
1. Саму задачу.
2. Что получилось.
3. В чем прошу помощи.
Как будет видно из кода, необходимо реализовать разреженный массив:
#include <cstdint>
#include <cassert>
#include <type_traits>
template<typename T, uint64_t Mask>
class SparseArray {
public:
using ElementType = T;
//Написать constexpr конструкторы:
//1. Дефолтный конструктор SparseArray()
//2. Конструктор, принимающий значения именно всех элементов прореженного массива
template<uint8_t Index>
constexpr T get() { //Возвращает элементы именно по значению, не по ссылке.
//Вернуть дефолтное значение T, если элемента нет в массиве, иначе вернуть существующий элемент из массива.
}
//Исключить оператор при помощи SFINAE если нет оператора + для пары T и TOther
template<typename TOther, uint64_t MaskOther>
constexpr auto operator +(const SparseArray<TOther, MaskOther>& other) {
//Вернёт новый SparseArray с поэлементной суммой двух исходных массивов
}
private:
T values[/*Посчитать размер прореженного массива*/];
};
int main() {
SparseArray<float, 3 > array0(1.0f, 2.0f);
SparseArray<double, 10> array1( 4.0, 7.0);
auto sum = array0 + array1;
static_assert(sizeof(sum) == sizeof(double) * 3, "Invalid sum array size");
static_assert(sizeof(array0) == sizeof(float) * 2, "Invalid array size");
static_assert(sizeof(array1) == sizeof(double) * 2, "Invalid array size");
assert((std::is_same_v<typename decltype(sum)::ElementType, double> == true));
assert(sum.get<0>() == 1.0);
assert(sum.get<1>() == 6.0);
assert(sum.get<2>() == 0.0);
assert(sum.get<3>() == 7.0);
SparseArray<float, 3> array2;
assert(array2.get<0>() == 0.0f);
assert(array2.get<1>() == 0.0f);
return 0;
}
Получилось всё, кроме реализации оператора сложения:
// My SparseArray implementation
#include <cstdint>
#include <iostream>
#include <cassert>
#include <utility>
#include <bitset>
template<typename T, uint64_t Mask>
class SparseArray
{
public:
using ElementType = T;
constexpr SparseArray()
: values() {
std::cout << "Default ctor" << '\n';
}
template<typename... Args>
constexpr SparseArray(Args&&... args)
: values{args...} {
std::cout << "Args ctor. Mask = " << Mask << '\n';
}
template<uint8_t Index>
constexpr ElementType get() const {
if(isSet(Index))
return values[countEntityNumber(Index)];
else
return T();
}
constexpr static std::size_t countEntityNumber (size_t index) {
uint64_t subMask{0};
for(uint64_t i = 0; i < index; ++i) {
subMask = subMask | 0b1;
if(i + 1 < index)
subMask <<= 1;
}
return popcount(Mask & subMask);
}
constexpr static std::size_t popcount (size_t value) {
return value != 0 ? (value & 0b1) + popcount(value >> 1) : 0;
}
constexpr static std::size_t isSet (size_t pos) {
return (Mask >> pos) & 0b1;
}
static const int mask = Mask;
static const int size = popcount(Mask);
ElementType values[size];
};
int main ()
{
SparseArray<float, 3> array0(1.0f, 2.0f);
SparseArray<double, 10> array1( 4.0, 7.0);
static_assert(sizeof(array0) == sizeof(float) * 2, "Invalid array size");
static_assert(sizeof(array1) == sizeof(double) * 2, "Invalid array size");
SparseArray<float, 3> array2;
assert(array2.get<0>() == 0.0f);
assert(array2.get<1>() == 0.0f);
return 0 ;
}
Прошу помочь с реализацией
operator+.
То что
я сделал, к сожалению, не компилируется.
Ошибка в попытке использования объекта в выражение
std::index_sequence.
Не получается всё в compile-time сделать.
Описал конкретно эту проблему
здесь.