listクラスのinsert()の引数について

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

要素を単純に最後に追加したいときに下記のように書くのは面倒なので、やっぱり末尾追加用の関数をつくることにしました。
int nums[5]={8,5,3,7,8};
slist slis;
slis.insert(slis.end(), nums, nums+5);


引数が3つのinsert()の引数の型はそれぞれ下記の通りなので、
insert(std::list::const_iterator _Where, std::list::size_type _Count, const int & _Val)

CODE:

template 

class slist :public std::list{
public:

	slist& add(size_type begor, const int endor){
		this.insert(this.end(), begor, endor);
	}
};
と書いてみました。
正常にビルドされたのですが、

CODE:

int main(){
	int nums[5]={8,5,3,7,8};
	slist slis;
	slis.add(nums, nums+5);
}
とすると

CODE:

------ ビルド開始: プロジェクト: slist, 構成: Debug Win32 ------
コンパイルしています...
main.cpp
c:\documents and settings\administrator\my documents\visual studio 2008\projects\slist\main.cpp(129) : error C2664: 'slist::add' : 1 番目の引数を 'int [5]' から 'unsigned int' に変換できません。(新しい機能 ; ヘルプを参照)
        with
        [
            SLIST=int
        ]
        この変換が可能なコンテキストはありません。
ビルドログは "file://c:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\slist\Debug\BuildLog.htm" に保存されました。
slist - エラー 1、警告 0
========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ==========
というエラーが出てしまいます。まあ、当然と言えば当然ですよね。でも
slis.insert(slis.end(), nums, nums+5);
のときはうまくいきましたよね。これはどうしてなのでしょうか?

白い時空
記事: 18
登録日時: 14年前

Re: listクラスのinsert()の引数について

投稿記事 by 白い時空 » 14年前

insert(std::list::const_iterator _Where, std::list::size_type _Count, const int & _Val)

これって_Whereの直前に_Count個の_Valを挿入するinsert関数じゃないですか?

第2,3引数がイテレータのinsert関数が別にあるはずです。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

白い時空さんありがとうございます。

CODE:

	slist& add(_Iter begor, _Iter endor){
		this.insert(this.end(), begor, endor);
	}
としてみたのですが

CODE:

error C2061: 構文エラー : 識別子 '_Iter'
と言われてしまいました。
最後に編集したユーザー MoNoQLoREATOR on 2011年8月09日(火) 17:44 [ 編集 1 回目 ]

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

ちなみに

CODE:

	slist& add(iterator begor, iterator endor){
		this.insert(this.end(), begor, endor);
	}
を一番最初にためしてみたのですが

CODE:

error C2664: 'slist::add' : 1 番目の引数を 'int [5]' から 'std::list::_Iterator' に変換できません
だと言われました。

白い時空
記事: 18
登録日時: 14年前

Re: listクラスのinsert()の引数について

投稿記事 by 白い時空 » 14年前

イテレータはテンプレートを使うので
template
これが関数の前に必要なのでは?

あと、return文を忘れてますよ。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

白い時空さんありがとうございます。
_Iter はイテレーターの一種なんですか?
std::list::iterator型の変数に_Iter型の変数を代入しようとしたら変換できないと言われたのですが・・・。
とりあえず_Iterを使う前に template を書けば良いということでしょうか?
関数の方はうまくいったのですが、構造体を宣言するときはコンパイルエラーが出てしまいました。

CODE:

#include 
#include 
#include 

template 

class slist :public std::list{

	template 
	struct ScopeData{
		_Iter begor;
		_Iter endor;
	}scoper;

public:
	
	template 
	ScopeData& scope(_Iter begor, _Iter endor){
		scoper.begor = begor;
		scoper.endor = endor;
		return scoper;
	}
};

int main(){
	int nums[5]={2,0,7,5,3};
	slist slis;
	slis.scope(nums, nums+5);
}
error C2143: 構文エラー : ';' が '識別子' の前にありません。
だそうです。その後にもずらずらとエラー文が続いているのですが、構造体の宣言を直せば良さそうです。

アバター
a5ua
記事: 199
登録日時: 14年前

RE: listクラスのinsert()の引数について

投稿記事 by a5ua » 14年前

std::list::insertは、3通りほどオーバーロードされています。

CODE:

// positionの位置にxを挿入する
iterator insert(iterator position, const T &x);

// positionの位置にxをn個挿入する
void insert(iterator position, size_type n, const T &x);

// positionの位置に[first, last)の要素を挿入する
template 
void insert(iterator position, InputIteratorType first, InputIteratorType last);
このうち、3番目はメンバ関数テンプレートになっており、
挿入位置を示すstd::list::iteratorと、入力の範囲を示す入力イテレータ(Input Iterator)を受け取ります。
入力イテレータとは、簡単に言うと、

CODE:

++it;		// インクリメントで次の要素を指す
T x = *it;	// *で値を取り出し、xにコピーする
といった操作が可能な型のことです。

関数テンプレートでは、与えた引数によって、テンプレートパラメータが推論されます。

CODE:

int main()
{
	std::list s;
	std::vector v(5);
	int a[5] = {1, 2, 3, 4, 5};

	// sの末尾にvの要素をすべて追加
	// InputIteratorType = std::vector::iterator
	s.insert(s.end(), v.begin(), v.end());

	// sの先頭にaの要素をすべて追加
	// InputIteratorType = int *
	// 1, 2, 3, 4, 5, 
	// ^              ^
	// a             a+5
	// 
	// 配列の名前は、先頭要素へのポインタとなる
	// a + nは、aのn個先の要素へのポインタである
	s.insert(s.begin(), a, a + 5);
}
さて、答えを書いてしまいますが、挿入する位置を末尾に固定したバージョンは、
3番目のinsertを使えば簡単に実装できます。(テンプレートパラメータの名前は、適当に決めてOKですが、なるべくわかりやすい名前をつけましょう)

CODE:

template 
class slist : public std::list
{
public:
	template 
	void add(InputIteratorType first, InputIteratorType last)
	{
		insert(end(), first, last);
	}
};

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

a5uaさん、とても丁寧な回答ありがとうございます。実はadd関数に関しては既に解決していたりします。
少し仕様変更して、現在は下のようなコードになっています。

CODE:

#include 
#include 
#include 

template 

class slist :public std::list{
	iterator itBeg;
	iterator itEnd;

	//エラーになります
	template 
	struct ScopeData{
		_Iter begor;
		_Iter endor;
	}scoper;

public:

	template 
	slist& add(_Iter begor, _Iter endor){
		insert(end(), begor, endor);
		return *this;
	}
	
	template 
	ScopeData& scope(_Iter begor, _Iter endor){
		scoper.begor = begor;
		scoper.endor = endor;
		return scoper;
	}
	
	SLIST& operator[] (const int &num){}//省略
	slist& operator &slist){}//省略
	slist& operator &list){}//省略
	slist& operator& operator &arr){}//省略

	slist& operator& operator= (const std::list &list){}//省略
	slist& operator= (const SLIST &ele){}//省略
	slist& operator= (const std::vector &arr){}//省略
	void reit(){}//省略
	void setit(const int num){}//省略
	void operator= (const int &num){}//省略
	void operator! (void){}//省略
	SLIST& inc(){}//省略
	SLIST& operator++ (void){}//省略
	SLIST& operator++ (int){}//省略
	SLIST& dec(){}//省略
	SLIST& operator-- (void){}//省略
	SLIST& operator-- (int){}//省略
};

int main(){
	int nums[5]={8,5,3,7,8};
	slist slis;
	std::vector vec;
	std::list lis;
	slis.scope(nums, nums+5);
}
operator+=は廃止して、かわりに<<を使って
slis << vec << lis;
のようにどんどん追加していけるようにしました。
しかしこれではnums配列や、vecの3番目から5番目まで といった「範囲を指定して追加」するということができないので、
scope()という関数をつくり、ScopeData型(構造体)の1つの変数として受け取れるようにしようと考えたわけです。
slis << slis.scope(nums, nums+5); //←こんな風に
本当はscope()はグローバルな関数にした方がよいのでしょうが引数が面倒くさそうなのでとりあえず今のところはメンバ関数にしています。
構造体の中に入力イテレータを受け取る変数をつくりたいのですが、一体どうすればよいのかわからなくて困っているところです。
最後に編集したユーザー MoNoQLoREATOR on 2011年8月10日(水) 21:20 [ 編集 1 回目 ]

アバター
a5ua
記事: 199
登録日時: 14年前

RE: listクラスのinsert()の引数について

投稿記事 by a5ua » 14年前

std::pairを使ってイテレータの組を表すのはどうでしょうか?
pairを生成するための、std::make_pairというヘルパ関数も標準で用意されています。

CODE:

#include 
#include 
#include 	// std::pair, std::make_pair

template 
class slist : public std::list
{
public:
	template 
	slist &operator &scope)
	{
		insert(end(), scope.first, scope.second);
		return *this;
	}
};

int main()
{
	int a[5] = {1, 2, 3, 4, 5};
	std::vector v(10, 7);
	slist s;
	s 
#include 

template 
class slist : public std::list
{
    template 
    struct ScopeData{
        _Iter begor;
        _Iter endor;
    };

public:

    template 
    ScopeData scope(_Iter begor, _Iter endor){
		ScopeData scoper = {begor, endor};
        return scoper;
    }

	 template 
	slist& operator &scoper){
        insert(end(), scoper.begor, scoper.endor);
        return *this;
    }
};

int main()
{
	int a[5] = {1, 2, 3, 4, 5};
	std::vector v(10, 7);
	slist s;
	s 
#include 

template 
class slist : public std::list
{
public:
	template 
	slist &add(InIt first, InIt last)
	{
		insert(end(), first, last);
		return *this;
	}
};

int main()
{
	int a[5] = {1, 2, 3, 4, 5};
	std::vector v(10, 7);
	slist s;
	s.add(a, a + 4).add(v.begin() + 3, v.begin() + 6);
}

余談ですが、コンテナや、イテレータのペアを“範囲オブジェクト”とみなす考え方は
boostのrangeライブラリなどで取り入れられています。

参考:letsboost::range
http://www.kmonos.net/alang/boost/classes/range.html

アバター
MoNoQLoREATOR
記事: 284
登録日時: 14年前
住所: 東京

Re: listクラスのinsert()の引数について

投稿記事 by MoNoQLoREATOR » 14年前

ありがとうございます。
そ、そういえばmake_pair()なんていう関数がありましたね! どこかで見た気がします。こういうときに便利だったんですね・・・。
add()関数だと  ( (slis << vec).add(~) << lis ).add(~) ・・・ というように括弧で囲わないと使えないので不便です。
slis << vec
<< make_pair(nums+1, nums+4)
<< lis
<< make_pair(vec+3, vec+6);
というようにどんどん繋げられたらスッキリしますよね。
そして、さすがboostさん わかっていらっしゃる・・・。

とりあえずこれでslistクラスは完成したと思います。バグがなければ。
ちゃんと意図通り動くことが確認できたら記事を書くので使いたい人は使ってください。(何人いるかな?)