【问题标题】:Generic equivalent to std function objects通用等效于 std 函数对象
【发布时间】:2012-04-09 00:34:58
【问题描述】:

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 中的某个地方吗?当然,它们写起来很简单,但我非常不喜欢复制库代码,尤其是像这样看似微不足道的东西。

编辑

关于我为什么想要这个而不是使用 lambdas 或其他函数对象生成方法的一些上下文:

因此,我正在编写一个通用的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&lt;generic_equal_to&gt; 部分,这会导致您实际上无法按类型指定boost::lambdaboost::phoenix 函数对象。我想一种解决方案可能是 decltype:

fusion::fused<decltype(_1 == _2)>()

这似乎很尴尬,甚至可能不起作用,具体取决于 boost::lambdaboost::phoenix 的实现方式 - 我真的不确定。

我知道您可以使用fusion::make_fused 来解决整个问题,但是您必须实例化函数对象。那么,我想到的解决方案将是一个非模板 equal_to 结构 - 我称之为我的 generic_equal_to

我知道这是一个非常微不足道的问题 - 毕竟,make_fused(_1 == _2) 可能会内联到与fused&lt;generic_equal_to&gt; 大致相同的程序集。我简直不敢相信在任何地方的 boost 或 STL 中都没有 generic_equal_to 函数对象,因此提出了这个问题。

【问题讨论】:

  • 我想你的意思是operator()(const T&amp; t, const U&amp; u)
  • +1,但我认为您找不到受支持的。问题很重要(我昨天刚刚在an answer 中写了这段代码),但它还不足以吸引 Boost 开发者,而且std::equal_to 的破坏程度还不够高,以至于标准化委员会会弃用它。
  • @AndrewTomazos-Fathomling 哈哈是的!尝试在没有计算机的情况下编写代码来检查我的语法总是让我在某个地方绊倒

标签: c++ templates generics boost stl


【解决方案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);
}

凤凰也一样:

#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() 上模板化。
  • 刚刚添加了一些理由说明我为什么不愿意使用boost::lambdaboost::phoenix
  • @Ayjay:只需使用make_fused。如果他们已经有了可以做更多的实用程序,他们就不会手动实现 stdlib 的东西。
【解决方案2】:

现在在 C++14 中有std::equal_to&lt;void&gt;(也可以用作std::equal_to&lt;&gt;

std::equal_to&lt;&gt;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 相等比较的结果。

Docs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-20
    • 2010-09-11
    • 2012-01-13
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多