2011-08-29 73 views
1

更换元仿函数我有一个Visual Studio 2008的C++应用程序,我想用一个boost ::凤凰lambda表达式来代替一元仿函数。用一个boost ::凤演员

在我的情况,我有包含字符串对象的列表。我想删除所有不符合指定字符串的对象。所以,我使用这样的算法:

struct Foo 
{ 
    std::string my_type; 
}; 

struct NotMatchType 
{ 
    NotMatchType(const std::string& t) : t_(t) { }; 
    bool operator()(const Foo& f) const 
    { 
     return f.my_type.compare(t_) != 0; 
    }; 
    std::string t_; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<Foo> list_of_foo; 

    /*populate with objects*/ 

    std::string some_type = "some type"; 

    list_of_foo.erase(
     std::remove_if(list_of_foo.begin(), 
         list_of_foo.end(), 
         NotMatchType(some_type)), 
     list_of_foo.end()); 

    return 0; 
} 

这工作正常。但是,我想清理我的代码位和摆脱NotMatchType函子和替换它用这样一个简单的lambda表达式:

using boost::phoenix::arg_names::arg1; 

list_of_foo.erase(
    std::remove_if(list_of_foo.begin(), 
        list_of_foo.end(), 
        arg1.my_type.compare(some_type) != 0), 
    list_of_foo.end()); 

很明显,这是行不通的。

我也曾尝试:(arg1->*&Foo::my_type).compare(some_type) != 0

,我需要做的,使升压什么:凤:演员看起来像一个Foo对象?

回答

3

给定两个字符串lhsrhs,则指定lhs == rhs在语义上等同于lhs.compare(rhs) == 0。换句话说,你的函子在做什么等于做f.my_type != t_。记住

有了这一点,你可以表达你想要的凤凰为:

bind(&Foo::my_type, arg1) =! ref(some_type) 

为了记录在案,你在凤凰城的演员调用成员compare。由于该成员属于std::string虽然,这不是你想要的。我可以得到以下工作:

typedef int (std::string::*compare_type)(std::string const&) const; 
compare_type compare = &std::string::compare; 
bind(compare, bind(&Foo::my_type, arg1), "") != 0; 

最后一行是最后的函子。但这并不好,因为没有可靠的方法来获取标准类型的重载成员的地址。换句话说,上面的第二行不能保证编译。

以供将来参考,我更喜欢lambda表达式调用一个重载成员时:

auto compare = [](std::string const& lhs, std::string const& rhs) 
{ return lhs.compare(rhs); }; 
// bind that functor and use it as a Phoenix actor etc 
+0

'arg1'不表示指针类型,因此,使用操作者' - > *'上它是形成不良的。 '(&arg1) - > *&Foo :: my_type!= ref(some_type)'应该可以工作。 – ildjarn

+0

lambda表达式(即11 C++的一部分)是可悲的是,无法在Visual Studio 2008中 – PaulH

+0

@ildjarn我不明白。 'operator - > *'过载;我已经显示的代码在我的结尾编译。 –

4

使用std::string::compare()直接从凤凰是很丑陋的,因为它的过载,我们需要它的地址:

phx::bind(
    static_cast<int (std::string::*)(std::string const&) const>(
     &std::string::compare 
    ), 
    phx::cref(some_type), 
    phx::bind(&Foo::my_type, arg1) 
) != 0 

然而,如果我们按照吕克的提示,并简单地比较对象的平等,它变得更易于管理:

phx::cref(some_type) != phx::bind(&Foo::my_type, arg1) 
+0

这与使用boost :: bind有什么不同吗? 'boost :: bind(&Foo :: my_type,_1)!= boost :: cref(some_type)'?另外,是否需要使用'cref'来阻止它执行副本? – PaulH

+2

@PaulH:是的,'boost :: bind'可以在这种情况下工作,但是'std :: bind'和'std :: tr1 :: bind'不会。是的,如果没有使用'ref'或'cref',则会进行复制。 – ildjarn