【问题标题】:How to make a std::map of data type to function pointer如何将数据类型的 std::map 制作为函数指针
【发布时间】:2015-05-22 20:13:34
【问题描述】:

我有这样的数据结构

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

变量min 和max 取决于type 的值。我想知道是否有办法创建std::map 之类的

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);

有没有办法创建这样一个具有不同返回数据类型的函数指针的映射?

最后我想用它来规范化值

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

我读过this post,看起来很相似,但不理解提议的想法,也许你可以举个例子。

编辑

我将对我正在尝试的内容添加更多解释。 struct Data 有一个字段 DataType_t type。根据type 的值,我需要正确转换min 和max 字段以使其正确表示为int 或float。一种可能的方法是

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

类似

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

终于在一些函数处理Data变量我可以做

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));
   }
}

您注意到代码与getMinOrMaxForXXXX 完全相同,除了返回和强制转换类型。我想过使用像

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

但问题是如何让地图获得指向特定专业的指针,例如

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

这可以帮助我简化流程函数中的函数代码

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

【问题讨论】:

  • @Jarod42 你能给我举个例子吗?我看不出 boost::variant 有什么帮助。
  • 您的示例代码不一致。如果 myMap 值是函数指针,为什么它们有 getMin、getMax 方法?
  • 抱歉@simon,编辑了我的问题以反映 myMap 值是指向函数的指针。我认为现在是一致的,关于如何构建这样一个地图的任何想法?
  • 好吧,因为 INT 属于 DataType_t,我假设它可以用作 myMap[SomeVariable] 其中 someVariable 属于 DataType_t。
  • @BRabbit27: 但是你现在是编译时那一行的返回类型吗?

标签: c++


【解决方案1】:

使用std::tuple&lt; std::pair&lt; DataType, std::function&lt; void() &gt; &gt; &gt; myMap;

然后实现按类型获取,请参见此处使用此技术的工厂示例: https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/Design/Factory.h

按类型获取请看这里: https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/Utilities/MPL/Tuple.h

从这里开始:

    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;
}

这是一个简单的例子,我从元组中取出第一个元素并执行函数。现在,我们需要使用类型来查找元素,而不是获取第一个元素。一点元编程:

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);
}

然后调用它看起来像:

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;
}

您可以替换函数的返回类型或函数本身。或者您可以保持原样并进行绑定,以防需要更多参数。

【讨论】:

  • 我无法理解你提出的想法,我不太习惯模板。可以举个例子吗?
  • 我为你添加了一个例子。不是真的基于你的代码,但你可以很快适应它。
【解决方案2】:

我会改用模板类:

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

所以你的函数变成了:

// 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;
}

和

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

如果你真的需要保持你的结构为

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

那么您必须在运行时在模板方法中进行检查:

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);
    }
}

【讨论】:

  • 如果我使用建议的模板方法,如何创建Data 的std::vector 以允许我使用不同类型的数据?说,std::vector&lt;Data&lt;?&gt;&gt; data; data.push_back(/*Data&lt;int&gt;*/); data.push_back(/*Data&lt;float&gt;*/);?
  • @BRabbit27:你不能这样,你可以创建一个基类,但是如果你不提供虚拟方法,你必须再次转换为正确的类型。 (并存储(智能)指针)。
猜你喜欢
  • 1970-01-01
  • 2010-12-27
  • 2013-06-30
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多