ページ 11

無題

Posted: 2008年12月31日(水) 18:37
by kaiten
タイトルが思いつかないので無題で失礼します。
自分では理解できない事態になってしまったので質問させていただきます。
現在下記のような関数を作っているのですが、エラーが発生してしまいました。エラーは関数の下に書きます。
環境はvista、VC++2008EEでDxLibを使用しています。
コンパイルは通るのですが、実行時に下記のエラーが発生してしまいます。
これ以外に必要な情報があったら記載するので教えてください。
template <typename T_container, typename T_function>
void for_each(T_container &rcontainer, T_function ...)
	{
	//T_function(*func)();
	va_list va1;
	va_list va2
	va_start(va1, rcontainer);
	va_start(va2, rcontainer);
	//for(int i=0;i!=n;++i)
	while(va_arg(va2, T_function)!=NULL)
		{
		std::for_each(rcontainer.begin(), rcontainer.end(), std::mem_fun_ref(va_arg(va1, T_function)));
		}
	va_end(va2);
	va_end(va1);
	}
esTh.exe の 0x016b4470 でハンドルされていない例外が発生しました: 0xC0000005: Access violation

Re:無題

Posted: 2008年12月31日(水) 19:14
by Justy
これテンプレートですよね?
実体化するためには実際に使わないといけないわけですが、
これすごい妙なコードになっていて、どーやって使うのかさっぱりわからないのですが。

Re:無題

Posted: 2008年12月31日(水) 19:50
by kaiten
マ、マジっすか……
現在動いてる状態のコードはこれとは若干違うのでそっちも書いときます。
自分自身テンプレートの理解があやふやなまま書いたのでとんでもないことになっててもおかしくないと言えばそうなのですが……少々ショックw
template <typename T_container, typename T_function>
void for_each(T_container &rcontainer, int n, T_function ...)
	{
	//T_function(*func)();
	va_list va1;
	va_start(va1, n);
	for(int i=0;i!=n;++i)
		{
		std::for_each(rcontainer.begin(), rcontainer.end(), std::mem_fun_ref(va_arg(va1, T_function)));
		}
	va_end(va1);
	}
使用時は
for_each(player,2,&Player::Move,&Player::Draw);
こんな感じに使ってます。

Re:無題

Posted: 2008年12月31日(水) 20:57
by Justy

>いたのでとんでもないことになっててもおかしくないと言えばそうなのですが

 いやいや、templateで可変引数というのは滅多に見かけない上に
va_startが2つもあったので、ちょっと面食らっただけです(w

 1つ目の方はどこが可変引数の終端なのかを知るのに va_arg()が NULLかで
チェックしていますが、これは呼び出し側で明示的に NULLを入れないと
ダメですよね?
 しかも va_startに参照型を渡している時点でOUTです。

 2つ目の方はすっきりして大分マシになっています。
 可変引数特有の型チェックが行われないことと nにマイナスを突っ込まれない限り
問題ないかと思います。


 で、問題は

>0x016b4470 でハンドルされていない例外が発生しました: 0xC0000005: Access violation

 これなんですよね。
 
 2つ目に変えたのであれば、別のどこか原因ではないでしょうか。
 例えばコンテナ側に入っている値に何か問題があるとか。
 もう少し再現可能なコードはないでしょうか?

Re:無題

Posted: 2008年12月31日(水) 21:04
by Justy
 ちなみにその手の可変的なことをするなら、こういう風に繋げると
コンパイルによる型チェックができますし、数を明示的に指定する必要もなくなりますよ。

[color=#d0d0ff" face="monospace]
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

template <typename Container>
struct ContainerCallMemberFunction
{
typedef Container ContainerType;

ContainerCallMemberFunction(ContainerType &c): m_pContainer(&c) {}

template <typename Func>
ContainerCallMemberFunction& operator << (Func f)
{
if(m_pContainer)
std::for_each(m_pContainer->begin(), m_pContainer->end(), std::mem_fun_ref(f));
return *this;
}

private:
ContainerType * m_pContainer;
};

template <typename Container>
ContainerCallMemberFunction<Container> MakeContainerCallMemberFunction(Container &c)
{
return ContainerCallMemberFunction<Container>(c);
}

struct Test
{
Test(int val_): val(val_) {}
int val;
void a() { std::cout << "a" << val << std::endl; }
void b() { std::cout << "b" << val << std::endl; }
void c() { std::cout << "c" << val << std::endl; }
};

int main(void)
{
std::vector<Test> v;
v.push_back(Test(100));
v.push_back(Test(200));
v.push_back(Test(300));

MakeContainerCallMemberFunction(v) << &Test::a << &Test::b << &Test::c;
return 0;
}[/color]

Re:無題

Posted: 2008年12月31日(水) 23:32
by kaiten
>esTh.exe の 0x016b4470 でハンドルされていない例外が発生しました: 0xC0000005: Access violation
エラーに関してはおかげさまで解決しました。
va_startに参照型を渡せないことが解ってなかったのが原因だったようです。

教えていただいた方法を試して感動した後に読んでみて解らなかった点があるので質問させてください。
まずひとつ、クラスではなくて構造体なのはなぜなのでしょうか?あと、構造体ってコンストラクタ持てましたっけ?
もう一つはContainerCallMemberFunction& operator << (Func f) の部分なのですがなぜ&が付いているかです。

Re:無題

Posted: 2008年12月31日(水) 23:52
by Justy

>まずひとつ、クラスではなくて構造体なのはなぜなのでしょうか?あと、構造体ってコンストラクタ持てましたっけ?

 classも structも unionもクラスキーが異なるだけで、全部クラスです。
 つまり、structはクラスキー structのクラス、ということです。
 クラスなので、コンストラクタを持てます。


>もう一つはContainerCallMemberFunction& operator << (Func f) の部分なのですがなぜ&が付いているかです。

 参照でなくても動くとは思いますが、参照を返した方が効率もいいかな、と。

Re:無題

Posted: 2009年1月01日(木) 00:09
by kaiten
>全部クラス
そうだったのですか。勉強が足りませんでした。精進します。

>参照
そういうことなのですか。効率を考えたことがなかったので考えが及びませんでした。

疑問も氷解し、やりたかったことの方法も教えていただけたので解決とさせていただきます。
Justyさん、本当にありがとうございました。