【问题标题】:Illegal operand error on a function pointer iterator函数指针迭代器上的非法操作数错误
【发布时间】:2021-12-08 09:12:30
【问题描述】:

我收到以下错误:

  1. '
  2. '>:非法,右操作数的类型为'const_Ty'

在下面的代码中。

它是函数指针映射上的一个相对简单的迭代器,其中函数的形式为void (Game::*)(UINT)。我根据浮点数检查该值,然后运行该函数。 问题似乎出在for 行,尽管我在其他地方有另一个基本相似的 for 循环,它可以正常工作。

using FuncPtr = void (Game::*)(UINT);
std::map<FuncPtr, float> funcDelayedTriggerMap;
void Game::PollProcessDelayedTriggers()
{
    for (std::map<FuncPtr, float>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
    {
        float currentS = m_timer.GetElapsedSeconds();
        if (it->second < currentS)
        {
            (this->*(it->first))(UINT_MAX);
            funcDelayedTriggerMap.erase(it->first);
        }
    }
}

【问题讨论】:

  • 成员函数指针 do not implement operator<, 所以它们不是有效的 std::map 键
  • 哦,谢谢。这正是我一直在寻找的答案。
  • 将 void* 存储在地图中,然后可以进行比较。见How to compare pointers?
  • @S.M.由于多重继承和虚拟继承,成员函数指针不保证是单个指针的大小。将其转换为 void* 将导致 undefined behaviour
  • 或者更直接地说:成员函数指针实际上并不是指向内存的指针。

标签: c++


【解决方案1】:

成员函数指针don't implement operator<,这是std::map使用的默认排序函数。

成员函数指针仅实现 operator== 和 operator!= 。

解决此问题的一种简单方法是使用单独的键并将函数指针放入映射的值中,例如:

std::map<int, std::pair<FuncPtr, float>>

或者,如果您不需要快速查找 std::map,也可以使用简单的向量:

std::vector<std::pair<FuncPtr, float>>

另一种方法是使用函数指针类型作为键:

using FuncPtr = void (Game::*)(int);

// Just a helper to get a unique type for each function pointer
template<FuncPtr ptr>
struct Tag {};

struct DelayedTrigger {
    FuncPtr ptr;
    float value;

    DelayedTrigger() : ptr(nullptr), value(0.0f) {}
    DelayedTrigger(FuncPtr _ptr, float _value) : ptr(_ptr), value(_value) {}
};

std::map<std::type_index, DelayedTrigger> funcDelayedTriggerMap;

void Game::PollProcessDelayedTriggers()
{
    for (std::map<std::type_index, DelayedTrigger>::iterator it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ++it)
    {
        float currentS = 1.0;
        if (it->second.value < currentS)
        {
            (this->*(it->second.ptr))(0);
            funcDelayedTriggerMap.erase(it->first);
        }
    }
}

这实质上是使用特定的函数指针作为唯一键。

然后您可以像这样添加新条目:

funcDelayedTriggerMap.emplace(typeid(Tag<&Game::DoIt>), DelayedTrigger{&Game::DoIt, 1.0f});
// or
funcDelayedTriggerMap[typeid(Tag<&Game::DoIt>)] = {&Game::DoIt, 1.0f};

并检查是否存在函数:

if(funcDelayedTriggerMap.contains(typeid(Tag<&Game::DoIt>))) {
  // ...
}

这只有在您知道要在编译时与地图一起使用的所有功能时才有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 2016-06-11
    相关资源
    最近更新 更多