【问题标题】:Bind2nd issue with user-defined class用户定义类的 Bind2nd 问题
【发布时间】:2013-07-21 20:30:45
【问题描述】:

我正在尝试学习如何将 bind2nd 与用户定义的类一起使用,但我遇到了一个错误,尽管我努力寻找其他资源寻求帮助,但我无法弄清楚如何解决。

我们将不胜感激,谢谢。

ma​​in.cpp

#include <algorithm>
#include <vector>

class F
{
public:
  int operator()(int a, int b)
  {
    return a * b;
  }
};

int main(void)
{
  std::vector<int> bases;

  for(int i = 0; i < 5; ++i)
    bases.push_back(i);

  std::transform(bases.begin(), bases.end(), bases.begin(), std::bind2nd(F(), 2));
  // Error C2664: '_OutIt std::transform<std::_Vector_iterator<_Myvec>,std::_Vector_iterator<_Myvec>,
  // std::binder2nd<_Fn2>>(_InIt,_InIt,_OutIt,_Fn1)' : cannot convert parameter 4 from
  // 'std::binder2nd<_Fn2>' to 'std::binder2nd<_Fn2>'
}

【问题讨论】:

  • 请注意,std::bind2nd 在 C++11 中已弃用。

标签: c++ bind2nd


【解决方案1】:

首先,您必须包含 functional 以使用活页夹功能。

其次,您需要将您的 operator() 指定为 const。

第三,为了获得类型特征信息,如 *first_argument_type* 等,最好从 std::binary_function 继承。

#include <algorithm>
#include <vector>
#include <functional>
#include <iterator>
#include <iostream>

struct F : public std::binary_function<int, int, int>
{
    int operator()(int a, int b) const
    {
        return a * b;
    }
};

int main(void)
{
    std::vector<int> bases;

    for(int i = 0; i < 5; ++i)
        bases.push_back(i);

    std::transform(bases.begin(), bases.end(), bases.begin(), std::bind2nd(F(), 2));

    // print it to stdout
    std::copy(bases.begin(), bases.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}

编辑

如果您可以访问支持 C++11 的编译器和标准库,您的向量填充代码可以轻松重写为:

std::vector<int> bases(5);
int i = 0;

std::generate(bases.begin(), bases.end(), [&i]() { return ++i; });

对于 C++11,有一个新的绑定器(从 boost::bind 移出)std::bind。这要灵活得多,如果您愿意,可以尝试一下。如:

using namespace std::placeholders;
std::transform(std::begin(bases), std::end(bases), std::begin(bases), 
               std::bind(F(), 2, _1));

(我刚刚从下面的答案中看到,a.lasram 提到了新的 std::bind。我不知道您的项目是否允许您使用新的 C++11 ,而不是旧的 C++03 功能。如果我是你,我会,如果你不被允许,那么(引用著名的 Alexandrescu 先生的话)“打电话给你的代理。”:))

顺便说一句。 Ryan(见 cmets)是绝对正确的,当他提到时,即使是我最精细的 std::generate 东西 ;) 也可以使用 iota 写得更短:

std::iota(bases.begin(), bases.end(), 1);

std::iota 在 numeric 中定义。所以你也必须包括在内。

希望对您有所帮助。

【讨论】:

  • @Leif 干杯,先生!感谢您接受它...请参阅我的更新以获取更多信息。您甚至可以将您的 std.begin() 交换为基于范围的开始和结束...
  • 其实向量填充代码可以通过调用std::iota进一步简化,如std::iota(std::begin(bases), std::end(bases), 0)
  • @RyanMcK 不是我第一次监督 iota...也许是因为它的简称 ;)
【解决方案2】:

这完成了 Stefan 的回答,他指出 std::bind 将 const 引用作为函子参数,因此 operator () 必须是 const。

现在,您的二进制函子必须适应std::bind2ndbind2nd 期望 F 类型定义为 first_argument_typesecond_argument_typeresult_type

class F
{
public:
    typedef int first_argument_type;
    typedef int second_argument_type;
    typedef int result_type;

    int operator()(int a, int b) const
    {
        return a * b;
    }
};

C++11 引入了std::bind 一种更通用、更灵活的解决方案,它没有这些必需的 typedef

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-23
    • 2022-01-16
    • 1970-01-01
    • 2014-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多