#include <iostream>

#include <array>
#include <functional>
#include <cstddef>

template<std::size_t N>
using intArray = std::array<int, N>;

template<std::size_t N>
using callbackType = 
std::function<intArray<N>(const intArray<N>&, int)>;

template <std::size_t N>
class BaseClass {
public:
	virtual intArray<N> CustomBehavior(const intArray<N>& user_array, int user_number) = 0;
protected:
	intArray<N> my_array = {0, 0};
};


template <std::size_t N>
class DerivedClass : public BaseClass<N> {
public:
	DerivedClass() = default;

	DerivedClass(callbackType<N> custom_f)
		: customCallback(std::move(custom_f))
	{}

	void SetCustomBehavior(callbackType<N> custom_f) {
		customCallback = std::move(custom_f);
	}

	intArray<N> CustomBehavior(const intArray<N>& user_array, int user_number) override {
		if (customCallback)
			this->my_array = customCallback(user_array, user_number);
		return this->my_array;
	}

private:
	callbackType<N> customCallback;
};

#include <cassert>

static constexpr std::size_t MySize = 2;
using myIntArray = intArray<MySize>;

myIntArray my_behavior(const myIntArray& input_array, int a) {
	return {a * input_array[0], a * input_array[1]};
}

int main() {
	myIntArray my_array = {1, 1};

	// Default constructor
	DerivedClass<MySize> foo_1;

	myIntArray bar_1 = foo_1.CustomBehavior(my_array, 2);
	assert(bar_1[0] == 0 && bar_1[1] == 0);

	// Custom constructor
	DerivedClass<MySize> foo_2(my_behavior);
	myIntArray bar_2 = foo_2.CustomBehavior(my_array, 2);
	assert(bar_2[0] == 2 && bar_2[1] == 2);

	// Custom behavior set later on
	DerivedClass<MySize> foo_3;
	foo_3.SetCustomBehavior(my_behavior);
	myIntArray bar_3 = foo_3.CustomBehavior(my_array, 2);
	assert(bar_3[0] == 2 && bar_3[1] == 2);

	std::cout << "OK";

	return 0;
}