如何将两个C ++ 11 std::function
与operator==
进行比较,如果所有true
都引用相同的函数指针,则返回function
?< / p>
答案 0 :(得分:15)
虽然这个提升常见问题解答条目Why can't I compare boost::function objects with operator== or operator!=?提供了一个基本原理,据我所知,它也适用于std::function。引用常见问题解答:
然后,它概述了类似于Preet的请求解决方案,接着说:boost :: function对象之间的比较不能“很好”地实现,因此不会实现。 [...]
当f和g存储的函数对象的类型没有运算符时会出现问题== [...]
并解释为什么必须在赋值运算符或构造函数中处理它,然后继续说:
所有这些问题都转化为boost :: function构造函数或赋值运算符中的失败,即使用户从不调用operator ==。我们不能对用户这样做。
更新
在Accessing the target of a tr1::function object中找到了一个标准基本原理,这个标准基本上很古老,但与提升常见问题解答一致并说:
operator ==对于C ++语言中的tr1 :: function是无法实现的,因为在没有用户帮助的情况下,我们没有可靠的方法来检测给定类型T是否为Equality Comparable。
答案 1 :(得分:13)
您实际上可以使用.target
:
template<typename T, typename... U>
size_t getAddress(std::function<T(U...)> f) {
typedef T(fnType)(U...);
fnType ** fnPointer = f.template target<fnType*>();
return (size_t) *fnPointer;
}
if (getAddress(f) == getAddress(g)) {...}
(参考:C++ trying to get function address from a std::function)
答案 2 :(得分:6)
您可以首先比较a
和b
,然后比较它们的.target_type()
,如果这些目标类型ID相同,那么您可以比较它们的.target()
指针。您可以使用不匹配的目标类型作为早期错误。
答案 3 :(得分:2)
如果std::function<T(U...)> f
是成员函数,fnPointer
将为空。
答案 4 :(得分:2)
请注意,函数的相等性(决定两个函数是否总是具有相同的可观察行为)是lambda演算中不可判定的问题(这就是许多编程语言禁止比较函数的原因)。
因此,即使==
测试编译,它最多只会测试代码是否相同(具有相同的地址),而不是比较的函数具有相同的行为。
答案 5 :(得分:1)
好吧,如果您不害怕黑客攻击,则可以执行以下操作:
// Simple function means no std::bind was used
bool IsSimpleFunction(std::function<void(Args...)> function)
{
typedef void(functionType)(Args...);
functionType** functionPointer = function.template target<functionType*>();
return functionPointer != NULL;
}
bool AreEqual(std::function<void(Args...)> left, std::function<void(Args...)> right)
{
const int size = sizeof(std::function<void(Args...)>);
std::byte leftArray[size] = { {(std::byte)0} };
std::byte rightArray[size] = { {(std::byte)0} };
std::byte* leftByte = (std::byte*) new (&leftArray) std::function<void(Args...)>(left);
std::byte* rightByte = (std::byte*) new (&rightArray) std::function<void(Args...)>(right);
// PrintFunctionsBytes(leftByte, rightByte, size);
// Here the HACK starts
// By resetting certain values we are able to compare functions correctly
// When values are reset it has the same effect as when these values are ignored
bool isSimpleFunction = IsSimpleFunction(left);
if (!isSimpleFunction)
{
ResetAt(leftArray, rightArray, 16);
}
ResetAt(leftArray, rightArray, 56);
ResetAt(leftArray, rightArray, 57);
// Here the HACK ends
for (int i = 0; i < size; i++, leftByte++, rightByte++)
{
if (*leftByte != *rightByte)
{
return false;
}
}
return true;
}
void ResetAt(std::byte* leftArray, std::byte* rightArray, int i)
{
leftArray[i] = (std::byte)0;
rightArray[i] = (std::byte)0;
}
// Only for debug
void PrintFunctionsBytes(std::byte* leftFirstByte, std::byte* rightFirstByte, unsigned long long size)
{
std::vector<std::byte> leftVector(leftFirstByte, leftFirstByte + size);
std::vector<std::byte> rightVector(rightFirstByte, rightFirstByte + size);
std::cout << "Left: ";
for (int i = 0; i < size; i++)
{
std::cout << i << ':' << (int)leftVector[i] << std::endl;
}
std::cout << "Right: ";
for (int i = 0; i < size; i++)
{
std::cout << i << ':' << (int)rightVector[i] << std::endl;
}
}
这已在MSVC和64位发行版配置中进行了测试。它适用于简单的函数,也可以将std :: bind转换为std :: function。
如果您使用不同的编译器或构建配置,则必须针对您的环境调整被忽略的字节。
答案 6 :(得分:0)
比较两个shared_ptr怎么样?
using MessageFilter = std::function<void(const int msgID)>;
static void onMessageReceived(const int msgID)
{
std::cout << "msg id => " << msgID << std::endl;
}
static void someFunc()
{
auto filter = std::make_shared<MessageFilter>(&onMessageReceived);
if (filter && *filter)
{
(*filter)(1234);
}
}
如您所见,'filter'是shared_ptr,因此很容易与另一个进行比较。