3

boost::algorithm::joinでの便利な結合を提供しますstd::vector<std::string>

結合を行う前に、true の場合、この機能を拡張しstd::vector<std::tuple<std::string,bool>>て結果を (文字列の場合) 一重引用符で囲むにはどうすればよいでしょうか。

これはループで行うのは難しくありませんが、標準アルゴリズムと C++11 機能(ラムダなど)を最大限に活用するソリューションを探しています。

可能であれば、ブーストの結合を引き続き使用します。 エレガンス/読みやすさ/簡潔さがより重要です。

コード

#include <string>
#include <vector>
#include <tuple>
#include <boost/algorithm/string/join.hpp> 

int main( int argc, char* argv[] )
{
  std::vector<std::string> fields = { "foo", "bar", "baz" };
  auto simple_case = boost::algorithm::join( fields, "|" );

  // TODO join surrounded by single-quotes if std::get<1>()==true
  std::vector<std::tuple< std::string, bool >> tuples =
   { { "42", false }, { "foo", true }, { "3.14159", false } };

  // 42|'foo'|3.14159 is our goal
}

編集

わかりました、私は以下のkassakの提案を取り、見てみましたboost::transform_iterator()-ブースト自身のドキュメントの例の冗長さに気が進まなかったので、試しstd::transform()ました-それは私が望んでいたほど短くはありませんが、うまくいくようです.

答え

#include <string>
#include <vector>
#include <tuple>
#include <iostream>
#include <algorithm>
#include <boost/algorithm/string/join.hpp> 

static std::string
quoted_join( 
    const std::vector<std::tuple< std::string, bool >>& tuples, 
    const std::string& join
)
{
    std::vector< std::string >  quoted;
    quoted.resize( tuples.size() );
    std::transform( tuples.begin(), tuples.end(), quoted.begin(),
        []( std::tuple< std::string, bool > const& t ) 
        {
            return std::get<1>( t ) ? 
                "'" + std::get<0>(t) + "'" :
                std::get<0>(t);
        }
    );
  return boost::algorithm::join( quoted, join );
}

int main( int argc, char* argv[] )
{
  std::vector<std::tuple< std::string, bool >> tuples =
  { 
    std::make_tuple( "42", false ), 
    std::make_tuple( "foo", true ), 
    std::make_tuple( "3.14159", false ) 
  };

  std::cerr << quoted_join( tuples, "|" ) << std::endl;
}
4

4 に答える 4

3

Boost.Rangetransformedアダプターを使用するのが最も簡単です。

#include <string>
#include <vector>
#include <tuple>
#include <iostream>
#include <algorithm>
#include <boost/algorithm/string/join.hpp> 
#include <boost/range/adaptor/transformed.hpp>

int main()
{
    std::vector<std::tuple< std::string, bool >> tuples =
    { 
        std::make_tuple( "42", false ), 
        std::make_tuple( "foo", true ), 
        std::make_tuple( "3.14159", false ) 
    };

  std::cout
      << boost::algorithm::join( 
                tuples | boost::adaptors::transformed(
                    [](std::tuple< std::string, bool > const &tup){
                        return std::get<1>(tup) ? 
                            "'" + std::get<0>(tup) + "'" :
                                  std::get<0>(tup);
                    }
                ), "|" )
      << std::endl;
}
于 2012-12-26T03:30:34.363 に答える
3

最初に書くmake_transform_range( old_range, functor )。最初のバージョンでは、 がイテレータold_rangeの astd::pairであると仮定しますが、理想的には、 を許容するものであるべきbegin(c)です。

そうすれば、答えは本当にきれいで効率的になります。作業中の範囲を取得し、実際に関数を呼び出さずに変換してから、join を呼び出します。

今は携帯電話を使っているので、かなり毛むくじゃらの文字を入力するのはmake_transform_range私を超えています。そしてかなり毛深いです。

これはあまり抽象化されていない試みです。

auto functor = []( my_pair const&p )->std::string {
  if (p.second) return quote( p.first );
  return p.first;
};
auto tbegin = boost::make_transform_iterator( b, functor );
auto tend = boost::make_transform_iterator( e, functor );
join(…);

...うまくいけば、私が恐れていたほど厄介ではありません。私はまだそれだけmake_transform_rangeの価値があると思いますが、1回限りではないかもしれません.

もう 1 つのアプローチは、ファンキーな構文をすべて使用したブースト レンジ ライブラリです。それはすでに範囲ベースの変換を持っています。

于 2012-12-22T12:50:41.167 に答える
1

結合を使用する場合は、コレクションをラップboost::transform_iteratorして、必要に応じて引用符を追加できます

于 2012-12-22T08:23:54.303 に答える