如何解决 std::function 没有运算符 == 的问题?

How to work around the fact that std::function has no operator==?

问题:如果不是编译不通过,下面的代码虽然不一定很快,但表达力和简洁性都很强。

它无法编译,因为您无法将 std::function 个实例与 operator==() 进行比较。 std::find() 正试图做到这一点。

当然,我可以采用完全不同的实现方式,但尽管我很固执,也很喜欢下面的代码,但我正在寻找 "closest as possible" 可行的东西。

谁可以为我提供对下面执行相同操作的代码的漂亮重写?

#include <functional>
#include <vector>

typedef std::function<bool(int)> Tester_t;
typedef std::vector<Tester_t> TesterSet_t;

bool Test(TesterSet_t &candidates, int foo)
{
    TesterSet_t dropouts;
    for( auto& tester : candidates )
    {
        if(!tester(foo))    
        {
            droputs.push_back(tester);
        }
    }

    while(!dropouts.empty())
    {
        // The following line is not compiling because std::function has no operator==()
        TesterSet_t::iterator culprit = 
            std::find( candidates.begin(), candidates.end(), dropouts.back() );
        candidates.erase(culprit);
        dropouts.pop_back();
    }
    return !candidates.empty();
}

这里不需要平等。随手擦除

for (auto it = candidates.begin(); it != candidates.end(); ) {
    if (! (*it)(foo) ) {
        it = candidates.erase(it);
    }
    else {
        ++it;
    }
}
return !candidates.empty();

这也将比问题中的版本更快,即使 operator== 是为 std::function 定义的。

如果您不需要删除候选人,您可以写:

bool Test(TesterSet_t &candidates, int foo)
{
    return std::any_of(candidates.begin(), candidates.end(), [&foo](Tester_t &tester) {
        return tester(foo);
    });
}

更新

好的,您需要删除候选人

bool Test(TesterSet_t &candidates, int foo)
{
    candidates.erase(
        std::remove_if(candidates.begin(), candidates.end(), [&foo](Tester_t &tester) {
            return !tester(foo);
        }),
        candidates.end()
    );
    return !candidates.empty();
}

正如其他人所说,您不需要为此比较 std::function。使用标准的 C++ 设施,这可以在两行中有效地(具有线性复杂性)实现:

bool Test(TesterSet_t &candidates, int foo)
{
    candidates.erase(std::remove_if(candidates.begin(), candidates.end(),
        [foo](Tester_t& f){ return !f(foo); }), candidates.end());
    return !candidates.empty();
}

简单的答案是 不是 在这种情况下使用 std::function<...> 而是像 std::function<...> 这样的东西,它确实定义了一个相等运算符。为 function<...> 定义相等运算符的方法是在构造时检测实际函数对象是否实际包含相等运算符,如果包含,则使对象具有可比性。否则,您要么会产生错误,要么会认为持有此特定函数对象类型的对象是无可比拟的。

然而,直接观察到大多数函数对象是不可比较的!例如,lambda 函数不可比较,std::bind()std::mem_fn() 也不会产生可比较的函数对象。同样,std::bind()std::mem_fn() 可以有自定义实现。没有办法使 lambda 函数具有可比性 除非 有一个空捕获,在这种情况下它们可以变成函数指针并可以进行比较。

平等感知函数对象的实现有点太长,无法快速输入响应。但是,您可以在 github for equality-comparable bind() and mem_fn(). See this answer 查看我的实现,以了解 std::function<...> 的相等比较版本的实现。如果 lambda 函数具有相同的签名并且所有捕获的值都是相等可比较的,那么也可能希望它们具有可比较性。

综上所述,如果可以避免这种需要,最好避免。但是,我遇到了一些用例,尽管有限制(即,并非所有函数对象都将被涵盖),可比较的 std::function<...> 还是相当方便的。