C++ 比较std::函数是否相等?

C++ 比较std::函数是否相等?,c++,c++11,function-pointers,std-function,C++,C++11,Function Pointers,Std Function,如果两个C++11std::functions与operator=,我如何比较它们,并返回true,如果这两个函数都引用同一个函数指针?您可以先比较a和b,如果它们的目标类型ID相同,然后你可以比较他们的指针。您可以使用不匹配的目标类型作为早期错误。for std::function将std::function与空指针进行比较,据我所知,标准没有提供任何有关原因的详细信息 尽管如此,这个boost常见问题解答条目提供了一个基本原理,据我所知,它也应该适用于。引用常见问题: boost::func

如果两个C++11
std::function
s与
operator=
,我如何比较它们,并返回
true
,如果这两个
函数都引用同一个函数指针?

您可以先比较
a
b
,如果它们的目标类型ID相同,然后你可以比较他们的指针。您可以使用不匹配的目标类型作为早期错误。

for std::function将std::function与空指针进行比较,据我所知,标准没有提供任何有关原因的详细信息

尽管如此,这个boost常见问题解答条目提供了一个基本原理,据我所知,它也应该适用于。引用常见问题:

boost::function对象之间的比较无法“很好地”实现,因此将无法实现。[……]

然后,它概述了要求的类似于Preet的解决方案,并接着说:

当f和g存储的函数对象类型没有运算符==[…]时,就会出现问题

并解释了为什么必须在赋值运算符或构造函数中处理此问题,然后说:

所有这些问题都会转化为boost::function构造函数或赋值运算符中的失败,即使用户从未调用运算符==。我们不能对用户这样做

更新

在中找到了一个标准的基本原理,它非常古老,但与boost常见问题解答一致,并表示:

运算符==对于C++语言中的Tr1:函数不可实现,因为我们没有可靠的方法来检测给定类型T是否相等而没有用户帮助。


实际上,您可以使用
。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)) {...}
模板
大小\u t获取地址(标准::函数f){
类型定义T(fnType)(U.);
fnType**fnPointer=f.template target();
返回(大小)*fn指针;
}
如果(getAddress(f)==getAddress(g)){…}

(Ref:)

如果
std::function f
是成员函数,则
fnPointer
将为空。

请注意,函数相等(确定两个函数是否始终具有相同的可观察行为)是lambda演算中不可判定的问题(这就是许多编程语言禁止比较函数的原因)


因此,即使编译了
=
测试,它最多也只能测试代码是否相同(具有相同的地址),而不是比较的函数是否具有相同的行为。

如果您不怕黑客攻击,您可以这样做:

// 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;
    }
}
//简单函数表示未使用std::bind
布尔IsSimpleFunction(std::function)
{
类型定义无效(函数类型)(参数…);
functionType**functionPointer=function.template target();
返回函数指针!=NULL;
}
布尔值相等(标准::函数左,标准::函数右)
{
常量int size=sizeof(std::function);
std::byte leftArray[size]={{(std::byte)0};
std::byte rightArray[size]={{(std::byte)0};
std::byte*leftByte=(std::byte*)新建(&leftArray)std::函数(左);
std::byte*rightByte=(std::byte*)新建(&rightArray)std::函数(右);
//打印功能字节(左字节、右字节、大小);
//黑客开始了
//通过重置某些值,我们能够正确比较函数
//重置值时,其效果与忽略这些值时相同
bool isSimpleFunction=isSimpleFunction(左);
if(!isSimpleFunction)
{
ResetAt(leftArray,rightArray,16);
}
ResetAt(leftArray,rightArray,56);
ResetAt(leftArray,rightArray,57);
//到此为止
对于(int i=0;i比较两个共享的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);
    }
}
使用MessageFilter=std::函数;
收到消息时静态无效(const int msgID)
{

std::cout那么
std::function::target
做什么呢?有趣的是,
boost::function
std::function
AFAIK允许更多的相等检查。似乎是:
std::function
的副本,不必引用函数指针。两个函数相等到底意味着什么?这是一个可疑的问题操作,甚至在进入
std::function
target()之前
需要知道存储的类型,而不仅仅是知道它是相同的。你是指函数的类型吗?因为我认为我实际上可以做到。神奇,谢谢。出于某种原因,我在不使用模板的情况下尝试为同一函数的两个std::function wrapper返回不同的函数指针。好奇!将函数指针转换为
size\u t
通过实现定义的语义有条件地得到支持。因此,此解决方案可能不可移植。只有当包装的对象是函数指针时,此解决方案才有效,而不是当它是可调用类或可由
std::function
包装的其他事物之一时。如果您知道目标的类型,则可能需要开始时不需要
std::function