(注:如果这个问题让人感觉像是一个X-Y问题,请滚动到下面的分隔符了解我提出这个问题的原因)
我正在寻找一种方法来存储不同类型的成员函数指针并比较它们是否相等。我需要将指向成员函数的指针映射到任意对象,并在该映射中进行搜索。它不必是关联容器,线性搜索就可以。还要注意,这些指针仅用作映射键,从不被解引用。
我的当前方法是:在构建映射时,我将传入的成员指针重新解释为一个众所周知的类型(void (MyClass::*)()
),然后将其插入到映射中。大致如下(为简洁起见省略了错误检查):
template <class R, class... A)
void CallChecker::insert(R (MyClass::*key)(A...), Object value)
{
mapping.push_back(std::make_pair(reinterpret_cast<void (MyClass::*)()>(key), value));
}
然后在查找时,我执行相同的转换并通过等式搜索:
template <class R, class... A)
Object CallChecker::retrieve(R (MyClass::*key)(A...)) const
{
auto k = reinterpret_cast<void (MyClass::*)()>(key);
auto it = std::find_if(begin(mapping), end(mapping), [k](auto x) { return x.first == k; });
return it->second;
}
然而,我不确定这种方法总是有效的。虽然我相信它不会产生错误的负面影响(将两个相等的指针报告为不同),但我担心它可能会产生错误的负面影响(当将两个原本不同类型的指针强制转换为“通用”类型时,它们可能会比较相等)。所以我的问题是,是否存在这种情况?或者我在使用这样的比较时是否安全?
我知道我正在接近未定义行为的领域。但是,我不介意使用标准未定义但在gcc和MSVC(我的两个目标编译器)中已知可行的行为来解决问题。
因此,问题是:通用类型的比较是否安全?还是说我最好将存储的指针强制转换为传入类型进行比较(如下所示):
template <class R, class... A)
Object CallChecker::retrieve(R (MyClass::*key)(A...)) const
{
auto it = std::find_if(begin(mapping), end(mapping), [key](auto x) { return reinterpret_cast<R (MyClass::*)(A...)>(x.first) == key; });
return it->second;
}
这两种方法实际使用起来都不可行,那我就没戏了吗?
我对指向成员的上述属性感兴趣,既是因为我的实际任务需要,也是为了加深我对该语言的理解。然而,出于完整性的考虑(以及万一有人知道更好的方法),以下是我提出这个问题的过程。
我正在构建一个实用框架来帮助单元测试Qt4信号(测试是否发出正确的信号)。我的想法是创建一个名为CallChecker的类,它将为插槽存储验证器(包装std :: function对象),并能够运行它们。测试将创建一个从此类派生的类;该类将定义运行相应验证器的插槽。以下是使用方法的示例(简化):
class MyTester : public QObject, public CallChecker
{
Q_OBJECT
public slots:
void slot1(int i, char c) { CallChecker::checkCall(&MyTester::slot1, i, c); }
void slot2(bool b) { CallChecker::checkCall(&MyTester::slot2, b); }
};
void testRunner()
{
MyTester t;
connectToTestedSignals(t);
t.addCheck(&MyTester::slot1, [](int i, char c) { return i == 7; });
}
我有一个工作实现(在ideone上使用gcc),其中
CallChecker
使用一对指针成员转换为通用函数类型的std::vector
。通过一些编译器标志的尝试(/vmg
),我也让它在MSVC上运行成功了。如果您能提出比指针成员查找更好的解决方案,我将非常乐意听取。我的目标是使实现测试槽的类易于使用:我真的希望这些槽只是简单的一行代码。使用槽签名的文本表示法(Qt在内部使用)并不是一个很好的选择,因为它太容易出现拼写错误。
boost::any
这种类型吗? - user2485710