How do you avoid code duplication when using varadic parameters in c ? Notice that I'm using templates recursively to achieve my goals, therefore I need some base cases and a recursive case. This creates a lot of code duplication, are there ways I could reduce this duplication?
Below, an example is provided of code that creates an arbitrary tensor (N dimensional array).
It's working fine but there's too much duplication. How can I avoid writing duplicated code when using template parameter packs recursively like this?
#include <cstddef>
#include <array>
#include <iostream>
template<typename T, std::size_t...>
class Tensor;
template<typename T, std::size_t N>
class Tensor<T, N> {
using Type = std::array<T, N>;
Type data;
public:
Tensor()
{
zero();
}
void zero()
{
fill(0);
}
Type::iterator begin() { return data.begin(); }
Type::iterator end() { return data.end(); }
void fill(T value)
{
std::fill(data.begin(), data.end(), value);
}
void print() const
{
std::cout << "[";
for(const auto& v : data)
{
std::cout << v << ",";
}
std::cout << "]";
}
};
template<typename T, std::size_t N, std::size_t M>
class Tensor<T, N, M>
{
using Type = std::array<Tensor<T, M>, N>;
Type data;
public:
Tensor()
{
zero();
}
void zero()
{
fill(0);
}
Type::iterator begin() { return data.begin(); }
Type::iterator end() { return data.end(); }
void fill(T value)
{
for(auto& v: data) {
std::fill(v.begin(), v.end(), value);
}
}
void print() const
{
std::cout << "[";
for(const auto& v : data)
{
v.print();
std::cout << ",";
}
std::cout << "]";
}
};
template<typename T, std::size_t N, std::size_t... M>
class Tensor<T, N, M...>
{
using Type = std::array<Tensor<T, M...>, N>;
Type data;
public:
Type::iterator begin() { return data.begin(); }
Type::iterator end() { return data.end(); }
Tensor()
{
zero();
}
void zero()
{
fill(0);
}
void fill(T value)
{
for(auto& v: data) {
v.fill(value);
}
}
void print() const
{
std::cout << "[";
for(const auto& v : data)
{
v.print();
std::cout << ",";
}
std::cout << "]";
}
};
CodePudding user response:
The only difference between a single-dimension tensor and a multiple-dimension tensor is the type of std::array
, T
for single and Tensor<T, M...>
for another.
template<typename T, std::size_t N, std::size_t... M>
class Tensor<T, N, M...> {
using InnerT = std::conditional_t<(sizeof...(M) > 0),
Tensor<T, M...>,
T>;
using Type = std::array<InnerT, N>;
Type data;
}
Then, use if constexpr
to distinguish single-dimension case,
void fill(T value)
{
if constexpr(sizeof...(M) > 0) {
for(auto& v: data) {
v.fill(value);
}
} else {
std::fill(data.begin(), data.end(), value);
}
}
void print() const
{
std::cout << "[";
for(const auto& v : data)
{
if constexpr(sizeof...(M) > 0) {
v.print();
std::cout << ",";
} else {
std::cout << v << ",";
}
}
std::cout << "]";
}