構造体のベクターの一部の要素のマージについて

[戻る]
ソイレントグリーン 2007/12/02(日) 22:13:39
いつもお世話になります、vector型で構造体データを持ち、その構造体の中のint型のデ
ータだけをマージをしたいのですが、下記のように書きましたら、このようなエラーが出
てしまうのですが、何処がおかしいのでしょうか?
ご教示お願い出来ませんでしょうか。

error C2100: 間接指定演算子 (*) の使い方が正しくありません。
コンパイルされたクラスの テンプレート のインスタンス化 '_OutIt 
std::_Merge<int,int,_OutIt,std::_Iter_random_helper3<_Cat1,_Cat2,_Cat3>::_Iter_r
andom_cat>
(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt,_InOutItCat,std::_Range_checked_iterator_tag
)' の参照を確認してください
        with
        [
            _OutIt=std::_Vector_iterator<int,std::allocator<int>>,
            _Cat1=std::_Int_iterator_tag,
            _Cat2=std::_Int_iterator_tag,
            
_Cat3=std::_Vector_iterator<int,std::allocator<int>>::iterator_category,
            _InIt1=int,
            _InIt2=int,
            
_InOutItCat=std::_Iter_random_helper3<std::_Int_iterator_tag,std::_Int_iterator_
tag,std::_Vector_iterator<int,std::allocator<int>>::iterator_category>::_Iter_ra
ndom_cat
        ]
コンパイルされたクラスの テンプレート のインスタンス
化 'std::_Vector_iterator<_Ty,_Alloc> 
std::merge<int,int,std::_Vector_iterator<_Ty,_Alloc>>
(_InIt1,_InIt1,_InIt2,_InIt2,_OutIt)' の参照を確認してください
        with
        [
            _Ty=int,
            _Alloc=std::allocator<int>,
            _InIt1=int,
            _InIt2=int,
            _OutIt=std::_Vector_iterator<int,std::allocator<int>>
        ]
error C2100: 間接指定演算子 (*) の使い方が正しくありません。
error C2100: 間接指定演算子 (*) の使い方が正しくありません。
error C2100: 間接指定演算子 (*) の使い方が正しくありません。
// VS2005 VC
#include <algorithm> 
#include <string> 
#include <vector> 

struct data {
  data(int d) : yymmdd(d) {} 
  int yymmdd; 
  std::string code; 
  double openprice;
}; 

int main() { 
  std::vector<data> v;
  v.push_back( data(1) ); 
  v.push_back( data(2) ); 
  v.push_back( data(3) );
  std::vector<data> v2; 
  v2.push_back( data(4) ); 
  v2.push_back( data(5) ); 
  v2.push_back( data(6) );
  std::vector<int> dist;
  std::vector<data>::iterator iter = v.begin();
  std::vector<data>::iterator iter2 = v2.begin();
  std::vector<int>::iterator distiter = dist.begin();

  std::vector<data>::iterator enditer = v.end();
  std::vector<data>::iterator enditer2 = v2.end();

  std::merge( iter->yymmdd, enditer->yymmdd, iter2->yymmdd, enditer2->yymmdd, 
distiter);
}

επιστημη [HomePage] 2007/12/02(日) 22:34:42
intのマージってどんな結果を期待していますか?
std::mergeはソート済みの二つのコンテナを一つのマージ済みコンテナにしちゃうんで
すけど。

ソイレントグリーン 2007/12/02(日) 22:39:59
επιστημηさん、お世話になります
>>intのマージってどんな結果を期待していますか?
私また勘違いしてますでしょうか?
今回の場合ですと、
std::vector<int> distコンテナに
1, 2, 3, 4, 5, 6を代入したいのですが

επιστημη [HomePage] 2007/12/02(日) 22:46:56
#include <algorithm> 
#include <string> 
#include <vector> 
#include <iterator>
#include <iostream>

struct data {
  data(int d) : yymmdd(d) {} 
  int yymmdd; 
  std::string code; 
  double openprice;
}; 

inline
bool operator<(const data& x, const data& y) {
  return x.yymmdd < y.yymmdd;
}

inline int pick_yymmdd(const data& x) {
  return x.yymmdd;
}

int main() { 
  std::vector<data> v;
  v.push_back( data(1) ); 
  v.push_back( data(3) ); 
  v.push_back( data(5) );

  std::vector<data> v2; 
  v2.push_back( data(2) ); 
  v2.push_back( data(4) ); 
  v2.push_back( data(6) );

  // vとv2をマージしてtempに
  std::vector<data> temp;
  std::merge(v.begin(), v.end(), v2.begin(), v2.end(), std::back_inserter
(temp));

  // tempからyymmddだけをとりだしてdistに
  std::vector<int> dist;
  std::transform(temp.begin(), temp.end(), std::back_inserter(dist), 
&pick_yymmdd);
  // 確認
  for ( int i = 0; i < dist.size(); ++i ) {
    std::cout << dist[i] << std::endl;
  }
}

επιστημη [HomePage] 2007/12/02(日) 22:48:18
>>intのマージってどんな結果を期待していますか?
> 私また勘違いしてますでしょうか?

きっと "思いっきり勘違い" してます。

ソイレントグリーン 2007/12/03(月) 00:16:10
お世話になります、
飲み込めなくてすみません、三点ほど質問させてもらってもいいでしょうか

※1
inline bool operator<(const data& x, const data& y) {
  return x.yymmdd < y.yymmdd;
}
ここでの>(比較演算子)のオーバーロードなのですが、何処で作用してますでしょう
か?

※2
merge関数の最期の引数ですが、επιστημηさんは
std::back_inserter (temp)を末尾挿入イテレータとして使われていると
思うのですが、格納方向を考えずに、イテレータtemp.begin()としますと
Assertionで落ちてしまうのですがこの使い方は間違いなのですね?

※3
先に私が書きましたiter->yymmddこの書き方はイテレータにはなってないという解釈で宜
しいでしょうか?

RAPT [HomePage] 2007/12/03(月) 00:34:02
> ※1
std::merge(v.begin(), v.end(), v2.begin(), v2.end(), std::back_inserter(temp));
でマージを行うときの比較演算子として。

> ※2
vector は末尾にしか追加できないから。

> ※3
YES. ただの値参照です。

ソイレントグリーン 2007/12/03(月) 01:08:32
RAPTさんの世話になります
※2、※3はよく分かりましたが
※1がmerge関数の処に比較演算子を書かなくても、作用するんですね、知りませんでし
た、merge関数で、比較関数を使う場合、私はこの様に書くものと思い込んでいました。
C++っぽくないですが^^;

inline bool compare(const data& x, const data& y) {
  return x.yymmdd < y.yymmdd;
}

std::merge(v.begin(), v.end(), v2.begin(), v2.end(), std::back_inserter (temp), 
&::compare);

επιστημη [HomePage] 2007/12/03(月) 01:34:03
> ※1 merge関数の処に比較演算子を書かなくても、作用するんですね

てゆーか、mergeに比較オブジェクトを書かないとき、operator < が適用される。
# ので、ちゃんと定義したらなあかん。

> ※2 std::back_inserter (temp)を末尾挿入イテレータとして使われていると
> 思うのですが、格納方向を考えずに、イテレータtemp.begin()としますと
> Assertionで落ちてしまうのですがこの使い方は間違いなのですね?

temp.size()がマージされる要素数より大きければ問題なし。
このサンプルでは temp.size()==0 なのでふっとぶ。

> ※3 iter->yymmddこの書き方はイテレータにはなってないという解釈で宜
しいでしょうか?

どうひいき目に見たところでイテレータじゃないわねぇ。
# おまけに end()->yymmdd はふっとぶし。

επιστημη [HomePage] 2007/12/03(月) 01:35:06
> C++っぽくないですが^^;

なぜに?

tetrapod 2007/12/03(月) 11:59:18
<algorithm> や <utility> は原理的にそんなに難しいことしてないので
# <iterator> とかのほうが難しい
ソース嫁といっておこう。

merge については (前提条件の表明等を除けば) これだけ。
oit merge(iit b1, iit e1, iit b2, iit e2, oit r) {
 while (b1!=e1 && b2!=e2) { // 元コンテナのどちらかが尽きるまで
  if (*b2<*b1) *r=*b2, ++b2; // 小さいほうをコピー
  else *r=*b1, ++b1;
  ++r;
 }
 // 片側コンテナが尽きているはずなので、残っているほうをコピー
 return copy(b2,e2, copy(b1,e1, r));
}
*b2<*b1 の判定の際に operator< (const T, const T) が暗黙に使われる

述語バージョンは *b2<*b1 が pred(*b2, *b1) に変わるだけ

C++ っぽいというのはこーいう話なのかな?
merge(v1.begin(), v1.end(), v2.begin(), v2.end(),
   std::back_inserter(r), std::less<data>());
これは述語として less<data> を指定しているわけだけど、結局のところ
less<T> は operator<(const data&, const data&) を使うことを述語として
明示しているだけであって operator < を実装する必要があることは同じ。

επιστημη [HomePage] 2007/12/03(月) 17:38:34
...あ、yymmddを抽出してからmergeしたほが簡単だわ♪

#include <algorithm> 
#include <string> 
#include <vector> 
#include <iterator>
#include <iostream>

struct data {
  data(int d) : yymmdd(d) {} 
  int yymmdd; 
  std::string code; 
  double openprice;
}; 

inline int pick_yymmdd(const data& x) {
  return x.yymmdd;
}

int main() { 
  std::vector<data> v;
  v.push_back( data(1) ); 
  v.push_back( data(3) ); 
  v.push_back( data(5) );

  std::vector<data> v2; 
  v2.push_back( data(2) ); 
  v2.push_back( data(4) ); 
  v2.push_back( data(6) );

  std::vector<int> dist;
  std::transform(v.begin(), v.end(), std::back_inserter(dist), &pick_yymmdd);
  std::transform(v2.begin(), v2.end(), std::back_inserter(dist), &pick_yymmdd);
  std::inplace_merge(dist.begin(), dist.begin()+v.size(), dist.end());
  // 確認
  for ( int i = 0; i < dist.size(); ++i ) {
    std::cout << dist[i] << std::endl;
  }
}

ソイレントグリーン 2007/12/05(水) 14:44:37
[[解決]]
お世話になります。
επιστημηさん
>なぜに?
なんとなくオーバーロードした多重演算子を使うと、いかにもC++っぽく思える
という、単なる個人的な主観です、オーバーロードの使い時というか、使うに相応しい
場面がよく、判っていない人なので、こういう時に使うのだなぁーと、すごく勉強にな
りました。
tetrapodさん
>ソース嫁といっておこう。
まったくですね、ただこの度、merge関数もですが、vector型のデータで
構造体のElementの更にその中のint型のオブジェクトに対するアクセス方法が、
ポカーンだったので、正直迷ったのですが、transform関数と比較演算子の合わせ業を御
教示して頂、原理もよく分かり、私にとって多きな収穫でした。
いつもとぼけた質問ばかりして申し訳ございませんが、大変ありがたく感じておりま
す。解決とさせて頂きます。
処でC++を深く学ぶ上で、Bjarne Stroustrup氏の『プログラミング言語C++第3版』とい
う本ですが、Amazonの書評とかを読みますと、難解な本で且つ、誤訳も多いという印象
を受けたのですが、皆さんのご意見はいかがなものでしょうか、ざっくりとで善いです
ので雑感、所感等を教えて頂けませんでしょうかお願いします。

επιστημη [HomePage] 2007/12/07(金) 10:10:57
> Bjarne Stroustrup氏の『プログラミング言語C++第3版』という本ですが、
> Amazonの書評とかを読みますと、難解な本で且つ、誤訳も多いという印象を
> 受けたのですが、皆さんのご意見はいかがなものでしょうか

書評の通り。誤訳については正誤表が出てるみたい。
難解なのは気にしない。初心者向けを狙ってるわけじゃないだろうから。

古いスレッドには追加発言できません。