にゃははー

はへらー

よく考えれば当たり前


例えば

struct hoge
{
    void fuga( void ) {}
};

reinterpret_cast< hoge * >( NULL )->fuga();

は通る+動く。まぁアーキテクチャ依存だろうけど。
つまりhoge::fuga()はコンパイル時に

static void fuga( hoge *this ) {}

fuga( reinterpret_cast< hoge * >( NULL ) );

ってなる。で、これだけを頭に入れて書いたコード

struct base
{
    virtual void fuga( void ) {}
};

struct derived
{
    void fuga( void ) {}
};

reinterpret_cast< derived * >( NULL )->fuga();

はセグフォになる。最初何をいわれてるか解らなかったけど、これって仮想関数テーブルを参照したときに死ぬなと。中途半端な知識は人を殺すな。

で、こんなことかこうと思ったのがソケットのラッパを書いてて、TCPUDPをそれぞれ作ってたとき

struct L4
{ ...
    virtual __socket_type protocol_type( void ) const = 0;
  ... };

struct TCP : public L4
{ ...
    __socket_type protocol_type( void ) const
    { return SOCK_STREAM; }
  ... };

struct UDP : public L4
{ ...
    __socket_type protocol_type( void ) const
    { return SOCK_DGRAM; }
  ... };

ってやってたとき

L4 *ptr;
...
if ( ptr->protocol_type() == reinterpret_cast< TCP * >( NULL )->protocol_type() )
{ ... }
...

で、乙。

static __socket_type protocol_type( void ) { ... }

って定義も混ぜるとオーバーロードが定義できないって怒られるし、このためだけにわざわざインスタンスを一つ作るのも馬鹿らしい。virtualな関数が[[final]]だったときに、それをstaticでも定義し直せるような仕様だったらいいんだがな・・・

結局

struct TCP;
struct UDP;
template < typename > __socket_type GetProtocolType( void );
template <> __socket_type GetProtocolType< TCP >( void ) { return SOCK_STREAM; }
template <> __socket_type GetProtocolType< UDP >( void ) { return SOCK_DGRAM; }

struct TCP : public L4
{ ...
    __socket_type protocol_type( void ) { return GetProtocolType< TCP >(); }
  ... };

struct UDP : public L4
{ ...
    __socket_type protocol_type( void ) { return GetProtocolType< UDP >(); }
  ... };

L4 *ptr;
...
if ( ptr->protocol_type() == GetProtocolType< TCP >() )
{ ... }
...

で落ち着いた。んーでもやっぱ同じ関数名の方が美しいよなぁ・・・