#include <iostream>
#include <vector>
#include <exception>
#include <array>
using namespace std;
namespace vmx_meta
{
template < typename T >
string TypeString(T var)
{ return "unhandled type"; }
template <>
string TypeString(double var)
{ return "double"; }
template <>
string TypeString(float var)
{ return "float"; }
template <>
string TypeString(int var)
{ return "int"; }
template <>
string TypeString(unsigned int var)
{ return "unsigned int"; }
template <>
string TypeString(std::string var)
{ return "std::string"; }
template <>
string TypeString(double *var)
{ return "double*"; }
template <>
string TypeString(int *var)
{ return "int*"; }
template <>
string TypeString(float *var)
{ return "float*"; }
// hack sale
template <>
string TypeString(const char *var)
{ return var; }
// ------------------------------------------
// variadic definition
// nil case first
string ArityShow()
{ return std::string(" /end"); }
// variadic general case
template < typename T, class ... ArgsType >
string
ArityShow(T firstArg, ArgsType ... arguments)
{
return TypeString(firstArg) + ArityShow(arguments ...);
}
};
// =============================================================================
// dummy typed image class (implemented likewise by many real image libs)
// =============================================================================
class Image
{
public:
enum class Type
{
Float64,
Float32,
Int32,
} type_;
std::size_t voxel_count_;
void *data_ptr_ = nullptr;
Image()
{}
void
allocate(Image::Type t, size_t voxel_count)
{
type_ = t;
voxel_count_ = voxel_count;
switch (t)
{
case Image::Type::Float64:
data_ptr_ = static_cast<void *>(new double[voxel_count]);
break;
case Image::Type::Int32:
data_ptr_ = static_cast<void *>(new int[voxel_count]);
break;
default:
throw;
}
}
void
set_data(Image::Type t, void *data)
{
if ( data_ptr_ != nullptr ) throw;
type_ = t;
data_ptr_ = data;
}
};
// =============================================================================
// Dispatcher mother, where all ropes are hidden from the user
// =============================================================================
template < class Derived >
class ExecutorMother
{
public:
Image *img_ = nullptr;
ExecutorMother(Image *img) : img_(img)
{}
template < class ... ArgsType >
void
operator()(ArgsType ... arguments)
{
if ( ExecutorMother::img_ -> data_ptr_ == nullptr ) throw;
Derived &derived = static_cast<Derived &>(*this);
switch (ExecutorMother::img_ -> type_)
{
case Image::Type::Float64:
{
derived . template filter_function<double>(arguments ...);
break;
}
case Image::Type::Float32:
{
derived . template filter_function<float>(arguments ...);
break;
}
case Image::Type::Int32:
{
derived . template filter_function<int>(arguments ...);
break;
}
default:
throw;// std::bad_exception;
}
}
};
// =============================================================================
// custom filter class
// =============================================================================
class CustomDispatcher : public ExecutorMother<CustomDispatcher>
{
public:
CustomDispatcher(Image *img) : ExecutorMother(img)
{}
template < typename ImgDataType >
void
filter_function(ImgDataType trigger_val, int iters, float dummy)
{
ImgDataType *data = static_cast<ImgDataType *>(ExecutorMother::img_ -> data_ptr_);
cout << endl << vmx_meta::ArityShow("filter datatype: ", data, " / arguments: ", trigger_val, " : ", iters, " : ", dummy);
for (size_t i = 0; i < ExecutorMother::img_ -> voxel_count_; i ++)
{
if ( data[i] == trigger_val )
data[i] = data[i] + iters;
}
}
};
// =============================================================================
// class use: main
// =============================================================================
int main()
{
std::array<int, 8> data = {1, 2, 3, - 32768, 5, 6, 7, 8};
Image imgd;
imgd . allocate(Image::Type::Float64, 2 * 4);
Image imgi;
imgi . allocate(Image::Type::Int32, 2 * 4);
CustomDispatcher execd(&imgd);
execd(- 32768, 32000, 3.14);
CustomDispatcher execi(&imgi);
execi(- 32768, 32000, 3.14);
return 0;
}