How to make std :: map data type for pointer function

I have a data structure like this

enum DataType_t{INT,FLOAT};
struct Data
{
   DataType_T type;
   void* min;
   void* max;
};

      

Variables min

and max

depend on the value type

. I want to know if there is a way to create std::map

like

std::map<DataType_t, SomeFcnPtr> myMap;
myMap[INT] = ?? // Here should be a pointer to a function like int(*FcnPtr)(Data d, bool min);
myMap[FLOAT] = ?? // Here should be a pointer to a function like float(*FcnPtr)(Data d, bool min);

      

Is there a way to create such a map with function pointers with different return types?

In the end, I want to use it to normalize values

float normalizedValue = (readValue - mayMap[INT](intData, true)) / (mayMap[INT](intData, false) - mayMap[INT](intData, true))

      

I am reading this post which looks very similar but did not understand the suggested ideas, maybe you could give an example.

EDIT

I'll add a little more explanation to what I'm trying. struct Data

has a field DataType_t type

. Depending on the value, type

I need to enter the fields correctly min

and max

so that their own views are int

or float

. One possible way could be

int getMinOrMaxForINT(Data aData, bool min)
{
   if(min) return *((int*)aData.min));
   return *((int*)aData.max));
}

      

and similarly

float getMinOrMaxForFLOAT(Data aData, bool min)
{
   if(min) return *((float*)aData.min));
   return *((float*)aData.max));
}

      

finally in some Data

variable handling function I could do

void someFunction(int value, Data aData)
{
   float normalizedValue = 0;
   if(aData.type == DataType_t::INT)
   {
      normalizedValue = (value - getMinOrMaxForINT(aData, true)) / (getMinOrMaxForINT(aData, false) - getMinOrMaxForINT(aData, true));
   }
   else if(aData.type == DataType_t::FLOAT)
   {
      normalizedValue = (value - getMinOrMaxForFLOAT(aData, true)) / (getMinOrMaxForFLOAT(aData, false) - getMinOrMaxForFLOAT(aData, true));
   }
}

      

since you noticed that the code is exactly the same for getMinOrMaxForXXXX

, except for return and cast types. I was thinking about using a template like

template <typename T>
T getMinOrMax(Data aData, bool min)
{
       if(min) return *((T*)aData.min));
       return *((T*)aData.max));
}

      

but the problem is how to get the map to get a pointer to a specific specialization like

myMap[DataType_t::INT] = //PointerTo getMinOrMax<int>
myMap[DataType_t::FLOAT] = //PointerTo getMinOrMax<float>

      

this could help me simplify the function code in process function

void someFunction(int value, Data aData)
{
   float normalizedValue = (value - myMap[aData.type](aData, true)) / (myMap[aData.type](aData, false) - myMap[aData.type](aData, true));
}

      

+3


source to share


2 answers


Use std::tuple< std::pair< DataType, std::function< void() > > > myMap;

Then we implement get by type using example with factory using this method: https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/Design/Factory.h

for getting by type look here: https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/MPL/Tuple.h

From now on:

    int retInt(){
  return 1;
}

float retFloat(){
  return 1.f;
}

char retChar(){
  return 'a';
}

int main(int, char *[])
{

  std::tuple< std::pair< int, std::function< int () > >,
             std::pair< float, std::function< float() > >,
             std::pair< char, std::function< char () > > > map;

  std::get<0>(map).second = retInt;
  int result = std::get<0>(map).second();
  return 0;
}

      



This is a simple example where I take the first element from a tuple and execute a function. Now instead of getting the first element, we need to find the element using the type. A bit of metaprogramming:

namespace detail{

template <class T, std::size_t N, class... Args>
struct get
{
  static const auto value = N;
};

template <class T, std::size_t N, class... Args>
struct get<T, N, T, Args...>
{
  static const auto value = N;
};

template <class T, std::size_t N, class U, class... Args>
struct get<T, N, U, Args...>
{
  static const auto value = get<T, N + 1, Args...>::value;
};

}

template <class T, class... Args>
std::pair< T, std::function< T() > >& get(std::tuple<Args...>& t)
{
    using Entry = std::pair<T, std::function<T()> >;
    return std::get<detail::get<Entry, 0, Args...>::value>(t);
}

      

Then the call to it will look like this:

int main(int, char *[])
{

  std::tuple< std::pair< int, std::function< int () > >,
             std::pair< float, std::function< float() > >,
             std::pair< char, std::function< char () > > > map;

  get< int >(map).second = retInt;
  int result = get<int>(map).second();

  get< float >(map).second = retFloat;
  float result2 = get< float >(map).second();

  return 0;
}

      

You can replace the return type of a function or the function itself. Or, you can keep it as is and bind if additional arguments are required.

+1


source


Instead, I would use a template class:

template <typename T>
struct Data
{
   T* min; // Do you really need pointer here ?
   T* max;
};

      

So your functions become:

// I would prefer split the function getMin(const Data<T>& aData)
// and getMax(const Data<T>& aData) or simply directly use (*aData.min)
template <typename T>
T getMinOrMax(const Data<T>& aData, bool min)
{
    return min ? *aData.min : *aData.max;
}

      

and



template <typename T>
float ComputeNormalizedValue(T value, const Data<T>& aData)
{
    return float(value - *aData.min) / (*aData.max - *aData.min);
}

      

If you really need to keep your structure as

enum DataType_t{INT,FLOAT};
struct Data
{
   DataType_T type;
   void* min;
   void* max;
};

      

then you have to do your check at runtime in your template methods:

template <typename T> bool isCorrectType(const Data& aData);
template <> bool isCorrectType<int>(const Data& aData) { return aData.type = INT;}
template <> bool isCorrectType<float>(const Data& aData) { return aData.type = FLOAT;}

template <typename T>
T getMin(Data aData, bool min)
{
    if (!isCorrectType<T>(aData)) { throw std::runtime_error("Bad type"); }
    return *((T*)aData.min));
}

template <typename T>
T getMax(Data aData, bool min)
{
    if (!isCorrectType<T>(aData)) { throw std::runtime_error("Bad type"); }
    return *((T*)aData.max));
}

template <typename T>
float ComputeNormalizedValue_impl(int value, const Data& aData)
{
    return float(value - getMin<T>(aData)) / (getMax<T>(aData) - getMin<T>(aData));

}

float ComputeNormalizedValue(int value, const Data& aData)
{
    switch (aData.type)
    {
        case INT: return ComputeNormalizedValue_impl<int>(value, aData);
        case FLOAT: return ComputeNormalizedValue_impl<float>(value, aData);
    }
}

      

0


source







All Articles