I have a family of complex functions performing very similar tasks except for one operator right in the middle of the function. A simplified version of my code could be something like that:
#include <assert.h>
static void memopXor(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] ^ buffer2[x];
}
};
static void memopPlus(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] + buffer2[x];
}
};
static void memopMul(char * buffer1, char * buffer2, char * res, unsigned n){
for (unsigned x = 0 ; x < n ; x++){
res[x] = buffer1[x] * buffer2[x];
}
};
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memopXor(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 1);
char res2[5] = {};
memopPlus(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memopMul(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
It looks like a good case to use C++ templates to avoid duplicating code, hence I was looking for a way to change my code to something like below (pseudo code):
#include <assert.h>
template <FUNCTION>
void memop<FUNCTION>(char * buffer1, char * buffer2, char * res, size_t n){
for (size_t x = 0 ; x < n ; x++){
res[x] = FUNCTION(buffer1[x], buffer2[x]);
}
}
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memop<operator^>(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 0);
char res2[5] = {};
memop<operator+>(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memop<operator*>(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
The hard point is that I'm not willing to accept any slowdown of the resulting code. It means solutions implying indirect calls (either through vtable or function pointers) are not OK.
The common C++ solution to this problem seems to be wrapping the operator to call inside the operator() method of a functor class. Typically to get something like the code below:
#include <assert.h>
template <typename Op>
void memop(char * buffer1, char * buffer2, char * res, unsigned n){
Op o;
for (unsigned x = 0 ; x < n ; x++){
res[x] = o(buffer1[x], buffer2[x]);
}
};
struct Xor
{
char operator()(char a, char b){
return a ^ b;
}
};
struct Plus
{
char operator()(char a, char b){
return a + b;
}
};
struct Mul
{
char operator()(char a, char b){
return a * b;
}
};
int main(int argc, char ** argv){
char b1[5] = {0, 1, 2, 3, 4};
char b2[5] = {0, 1, 2, 3, 4};
char res1[5] = {};
memop<Xor>(b1, b2, res1, 5);
assert(res1[0] == 0);
assert(res1[1] == 0);
assert(res1[2] == 0);
assert(res1[3] == 0);
assert(res1[4] == 0);
char res2[5] = {};
memop<Plus>(b1, b2, res2, 5);
assert(res2[0] == 0);
assert(res2[1] == 2);
assert(res2[2] == 4);
assert(res2[3] == 6);
assert(res2[4] == 8);
char res3[5] = {};
memop<Mul>(b1, b2, res3, 5);
assert(res3[0] == 0);
assert(res3[1] == 1);
assert(res3[2] == 4);
assert(res3[3] == 9);
assert(res3[4] == 16);
}
Is there any performance penalty to doing that ?