使用 for_each 和 bind 反转向量中的字符串

发布于 2024-08-05 18:13:25 字数 1012 浏览 3 评论 0原文

我想知道如何在一个“简单”行中使用单个 for_each 命令来反转 vector 中包含的 string

是的,我知道使用自定义函子很容易,但我不能接受,它不能使用 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*/);

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

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

I was wandering how it's possible to reverese strings that are contained in a vector using a single for_each command just in one "simple" line.

Yea, I know it is easy with a custom functor, but I can't accept, that it can't be done using bind (at least I couldn't do it).

#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*/);

Edit:
Thanks a lot for those funtastic solutions.
However, the solution for me was not to use the tr1::bind that comes with the Visual Studio 2008 feature pack/SP1. I don't know why it does not work like expected but that's the way it is (even MS admits that it's buggy). Maybe some hotfixes will help.

With boost::bind everything works like desired and is so easy (but sometimes relly messy:)). I really should have tried boost::bind in the first place...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

樱桃奶球 2024-08-12 18:13:25

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 和非常量变体,所以有必要对它们进行强制转换(正如 litb 在我写它们来测试我的答案时发现的那样......+1!)。这使得它非常冗长。 Typedef 可以让它变得更卫生一点,但要坚持一句简单的主题:

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。

std::for_each expects a unary function (or at least something with the typedefs of a unary function).

std::reverse<> is a binary function. It takes two iterators. It would be possible to bind it all together using boost::bind, but it would be a pretty horrible mess. Something like:

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

Better, I think, would be to write a reusable function called reverse_range like so:

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

(probably with some metaprogramming to ensure that Range& isn't a double-reference)

And then use that in your for_each (after adapting it to be a unary function, of course).

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

EDIT:

Because string::begin and string::end have both const and non-const variants, it is necessary to cast them (as litb discovered while I was off writing them to test my answer ... +1!). This makes it very verbose. Typedefs can make it a bit more sanitary, but to stick with the one-liner theme:

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)
    )
);

Which just screams for refactoring.

Finally, because I'm bored, bonus points for C++0x:

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

EDIT: boost::bind works just fine, no need for boost::lambda.

夏末染殇 2024-08-12 18:13:25

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

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

现在你可以用一行来做:

std::for_each(v.begin(), v.end(), Reverser());

You would have to roll your own reverse object:

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

Now you can do it one line:

std::for_each(v.begin(), v.end(), Reverser());
⊕婉儿 2024-08-12 18:13:25

使用 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

With Boost.Phoenix2:

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

To paraphrase mr-edd: measurably awesomer :)

Full example:

#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"));
}

prints:

olleh
dlrow
潦草背影 2024-08-12 18:13:25

也可以使用 BOOST_FOREACH 宏来完成:

BOOST_FOREACH( std::string& s, v )
    std::reverse( s.begin(), s.end() );

it could be also done with the BOOST_FOREACH macro:

BOOST_FOREACH( std::string& s, v )
    std::reverse( s.begin(), s.end() );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文