标准函数对象的通用等价物

4
有没有在boost中与std :: equal_to,std :: greater等函数对象家族通用的函数对象?
基本上,std :: equal_to应该变成类似于
struct generic_equal_to
{
    template <class T, class U>
    bool operator()(const T& t, const U& u) const
    {
        return t == u;
    }
};

我能理解std::plus等泛型版本可能更加棘手,因为存在返回类型问题(虽然decltype可以解决这个问题)。但是我无法想象std::equal_to函数对象本身需要模板参数的任何可能原因。
在boost或STL中肯定有这些版本存在,但我非常不喜欢复制库代码,尤其是对于这种看似微不足道的东西。
编辑:
以下是一些背景信息,说明我为什么想要这个而不是使用lambda或其他函数对象生成方法:
我正在编写一个通用的boost::fusion序列比较函数,如下所示:
template <class T>
bool sequence_equal(const T& left, const T& right)
{
    return fusion::all(
        fusion::zip(left, right),
        fusion::fused<generic_equal_to>());
}

请注意fusion::fused<generic_equal_to>部分,这导致您无法通过类型实际指定boost::lambdaboost::phoenix函数对象。我猜解决方案可能是使用decltype:
fusion::fused<decltype(_1 == _2)>()

不过这种方法看起来非常笨拙,而且也可能行不通,具体取决于boost::lambda或者boost::phoenix的实现方式——我真的不确定。

我知道你可以使用fusion::make_fused来解决这个问题,但是你必须实例化函数对象。那么我想到的解决方案是一个非模板的equal_to结构体,我把它叫做generic_equal_to

我知道这是一个非常微不足道的问题——毕竟,make_fused(_1 == _2)可能会内联到与fused<generic_equal_to>相同的汇编代码中。我只是无法相信在boost或STL中没有generic_equal_to函数对象,因此提出了这个问题。


2
我认为你的意思是 operator()(const T& t, const U& u) - Andrew Tomazos
1
+1,但我认为你不会找到受支持的解决方案。这个问题很重要(我昨天刚在一个答案中写了这段代码),但它不够吸引 Boost 开发人员,并且 std::equal_to 没有出现足够严重的问题,以至于标准化委员会不会弃用它。 - Potatoswatter
@AndrewTomazos-Fathomling 哈哈,是啊!试图在没有电脑检查语法的情况下编写代码总是会在某个地方绊倒我。 - Ayjay
2个回答

1

我认为没有什么比你要求的更直接了,但有些实用工具不仅可以满足你的使用情况,而且还可以超越它们。它们是Boost.LambdaBoost.Phoenix(后者是lambda库的更通用的继承者)。

使用Boost.Lambda进行通用相等性的示例:

#include <boost/lambda/lambda.hpp>
#include <iomanip>
#include <iostream>

struct foo {};

bool operator==(foo, foo) { return true; }
bool operator==(foo, int) { return false; }

template <typename T, typename U, typename Func>
void f(const T& x, const U& y, Func func)
{
    std::cout << func(x, y) << std::endl;
}

int main()
{
    using namespace boost::lambda; // for placeholders
    std::cout << std::boolalpha;

    foo a, b;
    int i = 0;

    f(a, b, _1 == _2);
    f(a, i, _1 == _2);
}

同样的,对于Phoenix:

#include <boost/phoenix.hpp>
#include <iomanip>
#include <iostream>

struct foo {};

bool operator==(foo, foo) { return true; }
bool operator==(foo, int) { return false; }

template <typename T, typename U, typename Func>
void f(const T& x, const U& y, Func func)
{
    std::cout << func(x, y) << std::endl;
}

int main()
{
    using namespace boost::phoenix::arg_names; // for placeholders
    std::cout << std::boolalpha;

    foo a, b;
    int i = 0;

    f(a, b, arg1 == arg2);
    f(a, i, arg1 == arg2);
}

每个操作符都可以通过明显的方式扩展以支持其他运算符(更普遍地,扩展到其他表达式中)。个人建议使用Phoenix,因为如果您发现需要的功能超出了Lambda提供的范围,您就不必同时包含两者。

是的,我知道还有其他生成函数对象的方法,但我的问题的重点是这些简单操作是否已经在某个地方定义了。它们确实被定义了,但它们都是在struct上进行模板化而不是在operator()上进行。 - Ayjay
刚刚为什么我不愿意使用 boost::lambdaboost::phoenix 添加了一些理由。 - Ayjay
@Ayjay:只需使用make_fused。如果已经有更多的实用程序,他们就不会手动实现stdlib的东西了。 - GManNickG

1

现在在C++14中,有std::equal_to<void>(也可以用作std::equal_to<>)。

std::equal_to<>是使用参数和返回类型推导的std::equal_to的一个特化版本。

template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
  -> decltype(std::forward<T>(lhs) == std::forward<U>(rhs));

返回 lhs 和 rhs 之间相等比较的结果。文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接