staticでは無いメンバ関数ポインタを、関数へ

[戻る]
tiha 2004/07/07(水) 19:20:27
例えば、関数ポインタを引数に取る関数functionがあるとして、

typedef void (*Callback)( int n );

void Function( Callback cb )
{
  cb( 100 );
}

というような。

このFunctionのcbへ、staticではないメンバ関数ポインタ、
例えば以下のHogeのFncメソッド

struct Hoge
{
  void Fnc( int n ){ cout << n << end; }
};

を渡すにはどうしたらよいのでしょうか?
typedefや、Functionが変更不可ということで。

Hoge hoge;
Function( ????? );

------
(vc6)

シャノン 2004/07/07(水) 20:01:11
#include <iostream>

struct Hoge
{
    void Callback( int n )
    {
        std::cout << n << std::endl;
    }
};

typedef void ( Hoge::*CALLBACK )( int );

void Test( CALLBACK func, Hoge *pHoge, int n )
{
    ( pHoge->*func )( n );
}

int main()
{
    Hoge hoge;
    Test( &Hoge::Callback, &hoge, 10 );
    return 0;
}

こんな感じで。
Hoge のインスタンスを渡してやらないと呼べません。
int main()
{
    Test( &CTest::Callback, &test, 10 );
    return 0;
}

シャノン 2004/07/07(水) 20:02:09
なんか下にごみが残ったね。
2つ目の main は無視してください。

シャノン 2004/07/07(水) 20:08:30
関数名変だけど気にしないでね…

シャノン 2004/07/07(水) 20:19:55
もうここまで来たら一人で書きまくってるの気にしないでどんどんいこー。

> typedefや、Functionが変更不可ということで。
void Fnc( int n ) と void Hoge::Fnc( int n ) は全然別物なので、typedef を変えな
いのは無理です。
Hoge のインスタンスが必要なので、Function を変えないのも無理です。

以下、関数名等を tiha さんのに極力合わせたサンプル。

#include <iostream>

struct Hoge
{
    void Fnc( int n )
    {
        std::cout << n << std::endl;
    }
};

typedef void ( Hoge::*CALLBACK )( int );

void Function( CALLBACK cb, Hoge &hoge, int n )
{
    ( hoge.*cb )( n );
}

int main()
{
    Hoge hoge;
    Function( &Hoge::Fnc, hoge, 100 );
    return 0;
}

鷲尾不徳 2004/07/07(水) 21:02:40
> typedefや、Functionが変更不可ということで。
Hoge::Fncは変えるな、と言及されてなかったので…
こんなのでどお?

#include <iostream>

typedef void ( *Callback )( int n );

void Function( Callback cb )
{
  cb( 100 );
}

void Fnc( int n )
{
  std::cout << n << std::endl;
}

struct Hoge
{
  Hoge():Fnc(::Fnc){};    //コンストラクタで関数ポインタ渡し
  Callback    Fnc;
};

int main( int,char** )
{
  Hoge hoge;
  Function( hoge.Fnc );
  return 0;
}

struct からの関数ポインタ渡しだったので咄嗟にこっちがでてきた。
BCCでは通りましたが・・・反則ですか?

tiha 2004/07/07(水) 21:03:38
[[解決]]
>void Fnc( int n ) と void Hoge::Fnc( int n ) は全然別物なので、
>typedef を変えないのは無理です。
>Hoge のインスタンスが必要なので、Function を変えないのも無理です。

無理ですか・・。それがわかっただけでもよかったです。
ありがとうございました。

static変数使う方法を一つみつけました。
#include <iostream>

struct Hoge
{
  static void* m_p;
    void Fnc( int n )
    {
        std::cout << n << std::endl;
    }
    static Callback( n );
    {
      Hoge* phoge = (Hoge*)m_p;
      phoge->Fnc( n );
    }
};
void* Hoge::m_p;

typedef void ( *CALLBACK )( int );

void Function( CALLBACK cb )
{
    cb( 100 );
}

int main()
{
    Hoge hoge;
    Hoge::m_p = &hoge;
    Function( &Hoge::Fnc );
    return 0;
}

て、ちと無理あるか・・

シャノン 2004/07/07(水) 21:21:49
エラー出ますよ(VC++.NET 2003)。
やっぱり、
void Func( int )
を取る関数に
void Hoge::Func( int )
は渡せません。

シャノン 2004/07/07(水) 21:27:44
↑のは、tiha さん@21:03:38 へのレスです。
で、鷲尾不徳 さん

それって、

#include <iostream>

typedef void ( *Callback )( int n );

void Function( Callback cb )
{
  cb( 100 );
}

void Fnc( int n )
{
  std::cout << n << std::endl;
}

int main( int,char** )
{
  Function( Fnc );
  return 0;
}

と同じじゃん。
呼び出す対象の Fnc が Hoge のメンバじゃないですもん。

tiha 2004/07/07(水) 21:42:57
あ、すいません。

> Function( &Hoge::Fnc );

は、
Function( &Hoge::Callback );

の間違いでした。

鷲尾不徳 2004/07/07(水) 21:44:36
>と同じじゃん。
>呼び出す対象の Fnc が Hoge のメンバじゃないですもん。

自分のじゃ、見た目それっぽく動くようにごまかしただけですね…

シャノン 2004/07/07(水) 21:50:30
そこまで言うならお目にかけよう、禁断の魔技!
…まともに動きゃしねぇがな。
よい子は真似しちゃいけないよっ☆

#include <iostream>
#include <cstdio>

struct Hoge
{
    void Fnc( int n )
    {
        std::cout << n << std::endl;
    }
};

typedef void ( *CALLBACK )( int );

void Function( CALLBACK cb, int n )
{
    ( *cb )( n );
}

int main()
{
    char s[ 80 ];
    std::memset( s, 0, 80 );
    std::sprintf( s, "%p", ( &Hoge::Fnc ) );

    long lPtr = std::strtol( s, NULL, 16 );
    CALLBACK pFunc = reinterpret_cast< CALLBACK >( lPtr );

    Function( pFunc, 100 );
    return 0;
}

シャノン 2004/07/07(水) 22:03:25
>tiha さん
Hoge に static な Callback を追加するのと、
Fnc 自体を static にするのはさほど変わらないような…

「Function と typedef を変更しない」にこだわるあまり
「コールバック関数のアドレスとして static でないものを渡す」が軽視されてます。

シャノン 2004/07/07(水) 22:20:32
禁断の魔技の sprintf / strtol がやってることを自力でやってみる。
使い物にならないことに変わりはない。

#include <iostream>
#include <cstdarg>

struct Hoge
{
    void Fnc( int n )
    {
        std::cout << n << std::endl;
    }
};

typedef void ( *CALLBACK )( int );

void Function( CALLBACK cb )
{
    ( *cb )( 100 );
}

void Test( int dummy, ... )
{
    va_list ap;
    va_start( ap, dummy );

    CALLBACK pFunc = va_arg( ap, CALLBACK );
    Function( pFunc );

    va_end( ap );
}

int main()
{
    Test( 0, &Hoge::Fnc );
    return 0;
}

シャノン 2004/07/07(水) 22:27:06
真っ当な方法ではどうやっても無理だと思います。
俺の禁断の魔技みたいな、真っ当じゃない方法でも可能性を模索しますか?
そうなるともはや、インラインアセンブラとか使わざるを得ない気がしますが。
俺はそっちはわかんないので、どなたか「やってみよう」と思う方がいらっしゃいまし
たらお願いします。

PATIO 2004/07/08(木) 09:40:20
というか、static関数で無いと渡せないのは呼び出した時に
必ずその関数が使える保障がいるからですよね。
で、メンバー関数はメンバー変数を使えるので
もしインスタンスが消滅した後で呼んでしまったら破綻します。
だから、メンバー変数の参照が行えないstaticにする必要があるわけです。
呼び出したい関数がメンバー変数を参照しない関数なら
staticにした所で不都合は無いでしょうし、
コールバックに使いたいならそうするべきです。

なので、メンバー関数をstatic関数しか渡せない所に引き渡そうという発想自体に
問題があると思いますよ。
渡せない理由を考えれば、答えは明白ですからね。

J 2004/07/20(火) 11:55:09
ソースの変更を最小限にするなら
boost::bind boost::function
を使う手もある。

#include <iostream>
#include <tchar.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>


typedef void (*Callback)( int n );

typedef boost::function<void (int)> Callbackfunc;

void Function( Callback cb )
{
  cb( 100 );
}

void Function( Callbackfunc cb )
{
  cb( 100 );
}


// 普通の関数
void func1(int n)
{
    std::cout << n << std::endl;
}

// メンバ関数
class bindtest
{
public:
    bindtest(int hoge) 
        : hoge_(hoge)
    {};
    ~bindtest(){};

    void func2(int n){
        std::cout << n << std::endl;
        std::cout << "member hoge : " << hoge_ << std::endl;
    };

private:
    int hoge_;
};


int _tmain(int argc, _TCHAR* argv[])
{
    // まずは、普通の関数の場合
    Function(&func1);

    // メンバ関数の場合
    bindtest memberfunc(230);
    boost::function<void (int)> f;
    f = boost::bind(&bindtest::func2, memberfunc, _1);

    Function(f);
    return 0;
}

お試しを

たく [E-Mail] 2004/07/20(火) 13:48:53
PATIOさんのコメントがすべてだと思うのですが、
結局解決されたんでしょうか?

tiha 2004/07/22(木) 14:32:42
[[解決]]
> [[解決]]
> >void Fnc( int n ) と void Hoge::Fnc( int n ) は全然別物なので、
> >typedef を変えないのは無理です。
> Hoge のインスタンスが必要なので、Function を変えないのも無理です。

> 無理ですか・・。それがわかっただけでもよかったです。
> ありがとうございました。

「無理」と言うことで解決させていただきました。
それと、いろいろな代替案、とても参考になりました。
みなさんありがとうございました。

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