【问题标题】:Problem with find_if on map地图上的 find_if 问题
【发布时间】:2011-05-06 07:59:00
【问题描述】:

我正在尝试在 std::map 上使用 std::find_if,寻找与字符串匹配的特定对象,如下所示:

class MyString
{
public:
    MyString() {}
    MyString(const std::string& x) : m_x(x) {}
    const std::string& value() const
    {
            return m_x;
    }

private:
    std::string m_x;
};

std::map<int,MyString> squaresS;
std::map<int,MyString>::iterator iIt;

squaresS[1] = MyString("1");
squaresS[2] = MyString("4");
squaresS[3] = MyString("9");
const std::string sTarget = "4";

iIt = std::find_if(squaresS.begin(), squaresS.end(),
    boost::bind(std::equal_to<std::string>(),
        boost::bind(&MyString::value,
            boost::bind(&std::map<int,MyString>::value_type::second, _1)),
        sTarget));

if (iIt != squaresS.end())
    std::cout << "Found " << iIt->second.value() << std::endl;
else
    std::cout << "Not Found" << std::endl;

执行这段代码的结果是Not Found;我希望 Found 4 被输出。但是,如果我使用整数做大致相同的事情,那么它可以工作,即输出是 Found 4:

class MyInteger
{
public:
    MyInteger() {}
    MyInteger(int x) : m_x(x) {}
    int value() const
    {
        return m_x;
    }

private:
    int m_x;
};

std::map<int,MyInteger> squaresI;
std::map<int,MyInteger>::iterator sIt;

squaresI[1] = MyInteger(1);
squaresI[2] = MyInteger(4);
squaresI[3] = MyInteger(9);
int iTarget = 4;

sIt = std::find_if(squaresI.begin(), squaresI.end(),
    boost::bind(std::equal_to<int>(),
        boost::bind(&MyInteger::value,
            boost::bind(&std::map<int,MyInteger>::value_type::second, _1)),
        iTarget));

if (sIt != squaresI.end())
    std::cout << "Found " << sIt->second.value() << std::endl;
else
    std::cout << "Not Found" << std::endl;

我怀疑这与 std::equal_to 有关,但我不确定如何解决此问题。

【问题讨论】:

  • 无关评论:有时我只是惊讶于人们会被这种可怕的难以理解的语法一步一步地陶醉的程度。可能是关于boost的沸腾青蛙故事。
  • @6502,我听到了...一个简单的函子会比这种绑定魔法更容易理解...&lt;sigh/&gt;
  • 实际上你上面的MyString 代码对我有用:ideone.com/DZ0lx,你仍然应该添加一个适当的复制构造函数!
  • @Nim:同意。 C++0x 几乎就在这里,几乎没有什么理由可以避免新代码中的新特性。当然,我有点害怕人们会用algorithm 和 lambdas 编写的那种代码,而 for 就足够了:想想 jQuery 对 JavaScript 开发所做的事情,你就会明白我的意思了。跨度>
  • 您的 MyString 代码也适用于 gcc-4.2.1

标签: c++ boost


【解决方案1】:

你可以这样做:

class MyString
{
public:
    MyString() {}
    MyString(const std::string& x) : m_x(x) {}
    const std::string& value() const
    {
            return m_x;
    }

private:
    std::string m_x;
};

class mystringmatch
{
   MyString _target;
public:
   mystringmatch(const MyString& target):_target(target)
   {
   }

   bool operator()(const std::pair<int, MyString>& src) const
   {
      return src.second.value() == _target.value();
   }
};

int _tmain(int argc, _TCHAR* argv[])
{
   std::map<int,MyString> squaresS;
   std::map<int,MyString>::iterator iIt;

   squaresS[1] = MyString("1");
   squaresS[2] = MyString("4");
   squaresS[3] = MyString("9");
   const std::string sTarget = "4";

   iIt = std::find_if(squaresS.begin(), squaresS.end(), mystringmatch(sTarget));

   if (iIt != squaresS.end())
       std::cout << "Found " << iIt->second.value() << std::endl;
   else
       std::cout << "Not Found" << std::endl;

    return 0;
}

在我看来,这种代码使人们从 C++ 转向其他语言。几乎无法阅读。

sIt = std::find_if(squaresI.begin(), squaresI.end(),
    boost::bind(std::equal_to<int>(),
        boost::bind(&MyInteger::value,
            boost::bind(&std::map<int,MyInteger>::value_type::second, _1)),
        iTarget));

【讨论】:

    【解决方案2】:

    正如其他人所指出的,您的代码已经适用于我(VC++ 2010 SP1)。也就是说,可以进行一个微不足道的更改来减少嵌套 binds 的数量——boost::bind 的返回类型(与 std::bind 的返回类型不同)具有所有关系和逻辑运算符重载,包括 operator== ,消除(或至少减轻)对像std::equal_to&lt;&gt; 这样的适配器的需求。利用这一点可以将您的代码简化为:

    typedef std::map<int, MyString> squares_t;
    squares_t::const_iterator iIt = std::find_if(
        squaresS.begin(),
        squaresS.end(),
        boost::bind(
            &MyString::value,
            boost::bind(&squares_t::value_type::second, ::_1)
        ) == sTarget
    );
    

    请参阅Boost.Bind docs 了解更多信息。

    【讨论】:

    • 谢谢,我使用 VC++ 2005 编译这个,所以我想是时候升级了!我喜欢你对 operator()== 的使用。
    猜你喜欢
    • 1970-01-01
    • 2022-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    相关资源
    最近更新 更多