6

我在徘徊,如何在一个“简单”行中使用单个命令来反转string包含在 a 中的 s 。vectorfor_each

是的,我知道使用自定义函子很容易,但我不能接受,它不能用它来完成bind(至少我做不到)。

#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> v; 
v.push_back("abc");
v.push_back("12345");

std::for_each(v.begin(), v.end(), /*call std::reverse for each element*/);

编辑: 非常感谢那些有趣的解决方案。但是,我的解决方案是不使用Visual Studio 2008 功能包/SP1 附带的tr1::bind 。我不知道为什么它不像预期的那样工作,但事实就是这样(甚至 MS 也承认它有问题)。也许一些修补程序会有所帮助。

使用 boost::bind 一切都按预期工作,而且非常简单(但有时会很乱:))。我真的应该首先尝试 boost::bind ......

4

4 回答 4

13

std::for_each 需要一个一元函数(或至少具有一元函数的 typedef 的东西)。

std::reverse<> 是一个二元函数。它需要两个迭代器。可以使用 boost::bind 将它们绑定在一起,但这将是一个非常可怕的混乱。就像是:

boost::bind(
    &std::reverse<std::string::iterator>,
        boost::bind(&std::string::begin, _1), 
        boost::bind(&std::string::end, _1))

我认为更好的是编写一个名为 reverse_range 的可重用函数,如下所示:

template <class Range>
void reverse_range(Range& range)
{
    std::reverse(range.begin(), range.end());
}

(可能通过一些元编程来确保 Range& 不是双重引用)

然后在你的 for_each 中使用它(当然,在将它调整为一元函数之后)。

std::for_each(v.begin(), v.end(),
    std::ptr_fun(&reverse_range<std::string>));

编辑:

因为 string::begin 和 string::end 都有 const 和 non-const 变体,所以有必要强制转换它们(正如 litb 在我写它们以测试我的答案时发现的那样...... +1!)。这使它非常冗长。Typedefs 可以使它更卫生一点,但要坚持单线主题:

boost::bind(
    &std::reverse<std::string::iterator>,
    boost::bind(
        (std::string::iterator (std::string::*)())&std::string::begin, _1),
    boost::bind(
        (std::string::iterator (std::string::*)())&std::string::end, _1)
    )
);

这只是尖叫重构。

最后,因为无聊,给 C++0x 加分:

std::for_each(v.begin(), v.end() [](std::string& s){ std::reverse(s); });

编辑: boost::bind 工作得很好,不需要 boost::lambda。

于 2009-09-30T09:59:28.740 回答
5

您必须滚动自己的反向对象:

struct Reverser
{
    void operator()(std::string& value) const
    {
        std::reverse(value.begin(),value.end());
    }
};

现在你可以做到这一点:

std::for_each(v.begin(), v.end(), Reverser());
于 2009-09-30T09:58:50.447 回答
5

使用Boost.Phoenix2

std::for_each(v.begin(), v.end(), boost::phoenix::reverse(arg1));

用 mr-edd 来解释:可测量的更棒 :)

完整示例:

#include <boost/spirit/home/phoenix.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>

int main(void)
{

    using namespace boost::phoenix::arg_names; // for "arg1"

    std::vector<std::string> v;
    v.push_back("hello");
    v.push_back("world");
    std::for_each(v.begin(), v.end(), boost::phoenix::reverse(arg1));

    std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}

印刷:

olleh
dlrow
于 2009-09-30T14:21:34.090 回答
3

也可以使用 BOOST_FOREACH 宏来完成:

BOOST_FOREACH( std::string& s, v )
    std::reverse( s.begin(), s.end() );
于 2009-10-03T14:40:16.027 回答