Adding Get/Set Logic to Bracket [] Operator Overloads in C++

Posted in software by Christopher R. Wirz on Tue Sep 25 2018



Modern language like C# allow for specifying setting and getting methods/logic for bracket [] operators, as well as multi-index bracket operators. C++ does not offer these features natively. Fortunately, these capabilities can be added without changing the external signatures/code what-so-ever.

Note: This may also be used when transferring values between system and device memory.

Let's assume you have a simple Threshold array, which stores values between a min and max. They way it should work, is that values higher are stored as the max, and values lower are stored as the min. Let's implement it the "old" way, leaving a TODO to add logic.


// ThresholdArray.hpp
#ifndef THRESHOLD_ARRAY_H
#define THRESHOLD_ARRAY_H
#include <stdlib.h>
template<typename T>
class ThresholdArray {
public:
    ThresholdArray(unsigned int size, T max, T min) { 
		this->size = size;
		this->max = max;
		this->min = min;
		values = (T*)malloc(size * sizeof(T));
		for (int n = 0; n < size; n++) { values[n] = min; }
	};
	~ThresholdArray() { free(values); values = NULL; };
    T & operator[](unsigned int i) {
		// TODO: add get/set logic
		return values[i % size];
	};
	void Print() {
		printf("(%d, %0.2f, %0.2f)\t: {", size, max, min);
		for (int n = 0; n < size - 1; n++) { printf("%0.2f, ", values[n]); }
		printf("%0.2f}\n", values[size - 1]);
	};
private:
	unsigned int size = 0;
	T max;
	T min;
	T* values;
};

// A specialization of Print for integers
template<>
void ThresholdArray<int>::Print()
{
	printf("(%d, %d, %d)\t: {", size, max, min);
	for (int n = 0; n < size - 1; n++) { printf("%d, ", values[n]); }
	printf("%d}\n", values[size - 1]);
}
#endif // THRESHOLD_ARRAY_H

We'll have to test out this class using a main() method.


#include "ThresholdArray.hpp"
int main()
{  
    // Make a ThresholdArray
    ThresholdArray<float> arr = ThresholdArray<float>(8, 6.0, 0.0);
    // Make a more limiting array
    ThresholdArray<int> arn = ThresholdArray<int>(8, 5, 1);
 
    for (int n = 0; n < 8; n++) {
        arr[n] = n;
        arn[n] = arr[n];
    }
    // Display the arrays
    arr.Print();
    arn.Print();
    getchar();
    return 0;
}

Running the initial main function produces the following code.


(8, 6.00, 0.00) : {0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00}
(8, 5, 1) : {0, 1, 2, 3, 4, 5, 6, 7}

As expected, the ThresholdArray does not work as desired. There are some incorret values in the arrays that are outside of the desired bounds. Fortunately, this can be fixed by adding a class to wrap the values, which we call ThresholdValue. The header file is updated as follows:


//ThresholdArray.hpp
#ifndef THRESHOLD_ARRAY_H
#define THRESHOLD_ARRAY_H
#include <stdlib.h>

template<typename T>
class ThresholdValue {
public:
	ThresholdValue(T* value, T max, T min) 
		{this->value = value; this->max = max; this->min = min; }
	operator T() const { return *value; }
	void operator = (const T val) { 
		if (val > max) { *value = max; }
		else if (val < min) { *value = min; }
		else { *value = val; }
	}
private:
	T max;
	T min;
	T* value;
};

template<typename T, unsigned int size, T max, T min>
class ThresholdArray {
public:
    ThresholdArray(unsigned int size, T max, T min) { 
		this->size = size;
		this->max = max;
		this->min = min;
		values = (T*)malloc(size * sizeof(T));
		for (int n = 0; n < size; n++) { values[n] = min; }
	};
	~ThresholdArray() { free(values); values = NULL; };
	ThresholdValue<T> operator[](unsigned int i) {
             	// A little pointer math to pass the value pointer
		return ThresholdValue<T>(values + (i % size), max, min);
	};
	void Print() {
		printf("(%d, %0.2f, %0.2f)\t: {", size, max, min);
		for (int n = 0; n < size - 1; n++) { printf("%0.2f, ", values[n]); }
		printf("%0.2f}\n", values[size - 1]);
	};
private:
	unsigned int size = 0;
	T max;
	T min;
	T* values;
};

// A specialization of Print for integers
template<>
void ThresholdArray<int>::Print()
{
	printf("(%d, %d, %d)\t: {", size, max, min);
	for (int n = 0; n < size - 1; n++) { printf("%d, ", values[n]); }
	printf("%d}\n", values[size - 1]);
}
#endif // THRESHOLD_ARRAY_H

Without any modifications to the main() function, it returns the following output:


(8, 6.00, 0.00) : {0.00, 1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 6.00}
(8, 5, 1) : {1, 1, 2, 3, 4, 5, 5, 5}

Everything seems to be working in the ThresholdArray class. Using the value wrapper, set and get logic can be added (in C++) without any changes to the code's signature.