6

単一のコマンドを使用して、単一の「単純な」行でstringに含まれる 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<> はバイナリ関数です。2 つの反復子が必要です。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 バリアントと非 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 は必要ありません。

于 2009-09-30T09:59:28.740 に答える
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 に答える
5

独自の反転オブジェクトをロールする必要があります。

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

これで、1行で実行できます:

std::for_each(v.begin(), v.end(), Reverser());
于 2009-09-30T09:58:50.447 に答える
3

BOOST_FOREACH マクロでも実行できます。

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