c++arraysinheritance

How to generically process std::array of different sizes


I have 2 classes which are very similar and I want to reduce code duplication by moving some functions to base class and inheriting from it.

The function has to process multiple arrays with different, compile-time known sizes. How can it be done generically without using std::vector?

I'd like to replace std::vector with std::array everywhere in this code example, because all the sizes are known in compile-time. I use base class only to reduce the code duplication, I don't really need polymorphism.

#include <vector>
#include <iostream>
class Base {
    public:
    Base(){}
    virtual ~Base(){}
    
    protected:
    
    virtual std::vector<int>& GetA() = 0;
    virtual std::vector<int>& GetB() = 0;
    void Foo() {
        for (const auto& el : GetA()) {
            std::cout<<el;
        }
        for (const auto& el : GetB()) {
            std::cout<<el;
        }
     }
};

class Impl1 : public Base {
    public:
    Impl1() : a_{1,2,3,4,5}, b_{12,13} {
        Foo();
    }
    ~Impl1() {}
    
    private:
    std::vector<int> a_;
    std::vector<int> b_;
    std::vector<int>& GetA() { return a_;}
    std::vector<int>& GetB() { return b_;}
};

class Impl2 : public Base {
    public:
    Impl2() : a_{0}, b_{1,2,3,4,5} {
        Foo();
    }
    ~Impl2() {}
    
    private:
    std::vector<int> a_;
    std::vector<int> b_;
    std::vector<int>& GetA() { return a_;};
    std::vector<int>& GetB() { return b_;}
};

Solution

  • If you want a base class just for code deduplication, it is recommended to avoid virtual and use templates instead. To tell users they should not use the base class, you can put it in namespace detail.

    Templates are also the way to parametrize std::array size, as they can be used with values and not just types - in fact, that is exactly how std::array is implemented.

    Here is an example:

    namespace detail {
        template <size_t SizeA, size_t SizeB>
        class Base {
            public:
            Base(const decltype(a)& a, const decltype(b)& b)
                : a{a}, b{b} {}
    
            void Foo() {
                for (const auto& el : a) {
                    std::cout << el;
                }
    
                for (const auto& el : b) {
                    std::cout << el;
                }
            }
    
            private:  // or protected, as you wish
            std::array<int, SizeA> a{};
            std::array<int, SizeB> b{};
        };
    }
    
    
    class Impl1 : public detail::Base<5, 2> {
        public:
        Impl1() : detail::Base{{1,2,3,4,5}, {12,13}} 
        {
            Foo();
        }
    
    };
    
    
    class Impl2 : public detail::Base<1, 5> {
        public:
        Impl2() : detail::Base{{0}, {1,2,3,4,5}}
        {
            Foo();
        }
    };