5

我有一个Models如下的向量:

struct Model
{
    std::string mName;
    // .......
};

给定一个代表模型名称的字符串,我想看看是否可以在向量中找到其中一个模型。

现在我有这个:

std::string assetName = "monkey";
std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::bind(&Model::mName, _1) == assetName);

但这不会进行不区分大小写的字符串比较。所以我读到了boost/algorithm/string.hpp, with boost::iequals, 正确地做到了这一点。

这是我使用它的尝试:

std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::iequals(boost::bind(&Model::mName, _1), assetName));

然而这并没有编译并报告数百行编译错误。我相信 std::find_if 期望只有一个参数的第三个参数函数。

有一个简单的解决方法吗?

编辑:我忘了提到我不能使用 C++11,但我可以使用 boost!

EDIT2:下面的答案似乎给了我这个编译错误,使用这个:

std::vector<Model>::iterator iter = std::find_if(mModels.begin(), mModels.end(), boost::bind(&boost::iequals<std::string, std::string>, boost::bind(&Model::mName, _1), assetName));


bind.hpp(69): error C2825: 'F': must be a class or namespace when followed by '::'
2>          bind\bind_template.hpp(15) : see reference to class template instantiation 'boost::_bi::result_traits<R,F>' being compiled
2>          with
2>          [
2>              R=boost::_bi::unspecified,
2>              F=bool (__cdecl *)(const std::string &,const std::string &,const std::locale &)
2>          ]
2>          resourcemanifest.cpp(24) : see reference to class template instantiation 'boost::_bi::bind_t<R,F,L>' being compiled
2>          with
2>          [
2>              R=boost::_bi::unspecified,
2>              F=bool (__cdecl *)(const std::string &,const std::string &,const std::locale &),
2>              L=boost::_bi::list2<boost::_bi::bind_t<const std::basic_string<char,std::char_traits<char>,std::allocator<char>> &,boost::_mfi::dm<std::string,Model>,boost::_bi::list1<boost::arg<1>>>,boost::_bi::value<std::string>>
2>          ]
4

1 回答 1

4

调用而不是绑定函数

boost::iequals(boost::bind(&Model::mName, _1), assetName)

绑定是一个红鲱鱼:这目前不是一个仿函数,而是一个函数调用。

您(不小心)试图立即调用它,并将布尔结果用作std::find_if. 当然,这是不正确的。

您绑定模型名称是正确的,但您仍然必须将实际调用绑定到iequals

这是Boost 用户邮件列表中的一个先前示例- 第一个 Google 结果为bind iequals.

尝试类似:

boost::bind(
   &boost::iequals<std::string,std::string>,
   boost::bind(&Model::mName, _1), // 1st arg to iequals
   assetName,                      // 2nd arg to iequals
   std::locale()                   // 3rd arg to iequals
)

注意模板参数推导在这里是不可能的;还请注意,我们必须boost::iequals显式提供 ' 的默认第三个参数,因为默认值不会为我们提供在绑定函数时能够省略参数的魔力。

完整的工作测试用例:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/algorithm/string/predicate.hpp>

struct Model
{
    Model(const std::string& name) : name(name) {};
    std::string mName() const
    {
        return name;
    }

private:
    std::string name;
};

int main()
{
    std::vector<Model> mModels;
    mModels.push_back(Model("a"));
    mModels.push_back(Model("b"));
    mModels.push_back(Model("c"));

    const std::string assetName = "B";

    std::vector<Model>::iterator it = std::find_if(
        mModels.begin(),
        mModels.end(),
        boost::bind(
            &boost::iequals<std::string,std::string>,
            boost::bind(&Model::mName, _1),
            assetName,
            std::locale()
        )
    );

    assert(it != mModels.end());
    std::cout << it->mName() << std::endl; // expected: "b"
}

(看到它在这里工作。)


那为什么我的原始代码有效呢?

boost::bind(&Model::mName, _1) == assetName中,操作符==在使用 withboost::bind魔术时被重载;尽管看起来您正在进行直接比较,但该比较实际上并未在 to 的参数中进行评估std::find_if,而是推迟到稍后进行(主要是通过执行bind您看不到的隐式)。

但是,在普通函数调用的情况下,例如 to boost::iequals,我们必须自己应用那个“魔法”,这就是上面的全部内容。

于 2013-05-01T09:50:18.150 回答