東方算程譚

Oriental Code Talk ── επιστημηが与太をこく、弾幕とは無縁のシロモノ。

目次

Blog 利用状況

ニュース

著作とお薦めの品々は

著作とお薦めの品々は
東方熱帯林へ。

あわせて読みたい

わんくま

  1. 東京勉強会#2
    C++/CLI カクテル・レシピ
  2. 東京勉強会#3
    template vs. generics
  3. 大阪勉強会#6
    C++むかしばなし
  4. 東京勉強会#7
    C++むかしばなし
  5. 東京勉強会#8
    STL/CLRによるGeneric Programming
  6. TechEd 2007 @YOKOHAMA
    C++・C++/CLI・C# 適材適所
  7. 東京勉強会#14
    Making of BOF
  8. 東京勉強会#15
    状態遷移
  9. 名古屋勉強会#2
    WinUnit - お気楽お手軽UnitTest

CodeZine

  1. Cで実現する「ぷちオブジェクト指向」
  2. CUnitによるテスト駆動開発
  3. SQLiteで組み込みDB体験(2007年版)
  4. C++/CLIによるCライブラリの.NET化
  5. C# 1.1からC# 3.0まで~言語仕様の進化
  6. BoostでC++0xのライブラリ「TR1」を先取りしよう (1)
  7. BoostでC++0xのライブラリ「TR1」を先取りしよう (2)
  8. BoostでC++0xのライブラリ「TR1」を先取りしよう (3)
  9. BoostでC++0xのライブラリ「TR1」を先取りしよう (4)
  10. BoostでC++0xのライブラリ「TR1」を先取りしよう (5)
  11. C/C++に対応した、もうひとつのUnitTestFramework ─ WinUnit
  12. SQLiteで"おこづかいちょう"
  13. STL/CLRツアーガイド
  14. マージ・ソート : 巨大データのソート法
  15. ヒープソートのアルゴリズム
  16. C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す
  17. .NETでマンデルブロ集合を描く
  18. .NETでマンデルブロ集合を描く(後日談)
  19. C++/CLI : とある文字列の相互変換(コンバージョン)
  20. インテルTBBによる選択ソートの高速化
  21. インテルTBB3.0 によるパイプライン処理
  22. Visual C++ 2010に追加されたSTLアルゴリズム
  23. Visual C++ 2010に追加されたSTLコンテナ「forward_list」
  24. shared_ptrによるObserverパターンの実装
  25. .NETでマンデルブロ集合を描く(番外編) ── OpenCLで超並列コンピューティング
  26. StateパターンでCSVを読む
  27. 状態遷移表からStateパターンを自動生成する
  28. 「ソートも、サーチも、あるんだよ」~標準C++ライブラリにみるアルゴリズムの面白さ
  29. インテルTBBの同期メカニズム
  30. なぜsetを使っちゃいけないの?
  31. WPFアプリケーションで腕試し ~C++でもWPFアプリを
  32. C++11 : スレッド・ライブラリひとめぐり
  33. Google製のC++ Unit Test Framework「Google Test」を使ってみる
  34. メールでデータベースを更新するココロミ
  35. Visitorパターンで遊んでみたよ
  36. Collection 2題:「WPFにバインドできる辞書」と「重複を許す検索set」
  37. Visual C++ 2012:stateless-lambdaとSQLiteのぷち拡張
  38. 「Visual C++ Compiler November 2012 CTP」で追加された6つの新機能

@IT

  1. Vista時代のVisual C++の流儀(前編)Vista到来。既存C/C++資産の.NET化を始めよう!
  2. Vista時代のVisual C++の流儀(中編)MFCから.NETへの実践的移行計画
  3. Vista時代のVisual C++の流儀(後編) STL/CLRによるDocument/Viewアーキテクチャ
  4. C++開発者のための単体テスト入門 第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?
  5. C++開発者のための単体テスト入門 第2回 C++アプリケーションの効率的なテスト手法(CppUnit編)
  6. C++開発者のための単体テスト入門 第3回 C++アプリケーションの効率的なテスト手法(NUnit編)

AWARDS


Microsoft MVP
for Visual Developer - Visual C++


Wankuma MVP
for いぢわる C++


Nyantora MVP
for こくまろ中国茶

Xbox

Links

記事カテゴリ

書庫

日記カテゴリ

アヒル型

ネタ元 → カチカチからゆるゆるに

ダックタイピング : アヒル型付け
"If it walks like a duck and quacks like a duck, it must be a duck"
(もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである)

C++におけるtemplateはまさにこのダックタイピングなのね。

#include <iostream>

template<typename Object>
void try_sound(const Object& object) {
  object.sound();
}

class Duck {
public:
  void sound() const { std::cout << "くゎっくゎっ\n"; }
};

class Bomb {
public:
  void sound() const { std::cout << "ちゅどーん\n"; }
};

int main() {
  try_sound(Duck());
  try_sound(Bomb());
}

DuckとBombはメソッドsound()をメンバに持つ基底クラスから導出されている
わけでもなく、sound()を提供するinterfaceを実装しているわけでもなく、
sound()ってメソッドを持っているだけでtry_soundに食わせられます。
そこがダックタイピングなの。
templateの場合静的なダックタイピングなんですけども。

投稿日時 : 2007年8月30日 1:26

コメントを追加

# re: アヒル型 2007/08/30 1:29 中博俊

まさにしたり

# re: アヒル型 2007/08/30 1:30 中博俊

VB9がDuck Typingサポートをパスしちゃったのは惜しい。

# re: アヒル型 2007/08/30 2:49 シャノン

動的インターフェイスは面白かったのに残念。

# re: アヒル型 2007/08/30 9:04 とりこびと

>VB9がDuck Typingサポートをパスしちゃったのは惜しい。

実は一段階慣れが入ると助かるような気もしていたりw

# [C++] 2007/08/30 10:27 低学歴無能俸給生活者が数学とプログラミングを出来るようになりたいと独学している日記

http://blogs.wankuma.com/episteme/archive/2007/08/30/92662.aspx επιστημηさんは触れられていませんが,C++では動的なダックタイピングも実現出来ますね.

# re: アヒル型 2007/08/30 11:11 επιστημη

え? RTTIっちゅーかリフレクションを持たずにどぉやってアヒルと見做すんだろ?
だれかわかりる?わからりる?

# re: アヒル型 2007/08/30 13:56 uskz

こんな感じです.(他にも方法はありますが)

#include <iostream>

struct soundable
{
private:
struct soundable_holder_base
{
virtual ~soundable_holder_base()
{ }

virtual void sound() const = 0;
};

template <class T>
struct soundable_holder :
soundable_holder_base
{
T obj_;

soundable_holder(T const& obj) :
obj_(obj)
{ }

virtual void sound() const
{
obj_.sound();
}
};

soundable_holder_base* soundable_holder_;
public:
template <class T>
soundable(T const& obj) :
soundable_holder_(new soundable_holder<T>(obj))
{ }

~soundable()
{
delete soundable_holder_;
}

void sound() const
{
soundable_holder_->sound();
}
};


void try_sound(soundable const& object)
{
object.sound();
}

class Duck
{
public:
void sound() const { std::cout << "くゎっくゎっ\n"; }
};

class Bomb
{
public:
void sound() const { std::cout << "ちゅどーん\n"; }
};

int main()
{
try_sound(Duck());
try_sound(Bomb());
}

# re: アヒル型 2007/08/30 13:56 uskz

うわすいません空白文字消えるんですね.

# re: アヒル型 2007/08/30 13:59 とっちゃん

>リフレクションを持たずにどぉやって
わかんねーっすw

C++ の RTTI は型名までしかわからんし...
あるとしたら...COM(というより、IDispatch)?
でも、あれは C++ じゃないしなぁ...

せいぜい、(C++の)インターフェース...
ってそれは違うもんなぁ...
やっぱりわかんねーっす。

# re: アヒル型 2007/08/30 14:19 επιστημη

...それで動的にアヒル型付けできてんのかなぁ。
class NoSound {};
try_sound(NoSound());
ってやったらコンパイル・エラーなんやから、
これって静的なんとちゃうかしら。

動的にやるんだったら、実行時に例外吐くのがスジちゃいますやろか。

# re: アヒル型 2007/08/30 14:25 uskz

同じインタフェースを持ったオブジェクトを継承階層の有無に関わらず実行時に交換可能だというのが私の動的なduck typingに対する認識だったのですが,誤解してましたかね.

# re: アヒル型 2007/08/30 14:38 επιστημη

いや僕もよぉわからんです。あたしゃ:

void try_sound(object なにか) {
 // なにか はアヒルと見做せるか?
 if ( なにか に対してsound()できる ) {
  なにか.sound();
 }
}

ってやれることが動的なduck-typingだと思ってたんだけども...
そうでないとただのvirtual関数callだし、
アヒルか否かを実行時に判断できんのやったら
静的アヒル型付けとどこがちゃうん? て思うです。
# 自信ないんだけども^^;

# re: アヒル型 2007/08/30 15:09 επιστημη

> 同じインタフェースを持ったオブジェクトを継承階層の有無に関わらず実行時に交換可能

ならば try_sound( 投げたコインが表 ? Duck():Bomb());
って書けなきゃダメじゃなくね? とも思うし。

# re: アヒル型 2007/08/30 15:19 とっちゃん

ありゃ。おいらのコメントが...妙な位置にハマっちまってるw


おいらも、エピさん同様、動的に解決=実行時にオブジェクト(変数とかでもよい)などからそれと識別する手段を持つ
という解釈でいます。

だから、printf() は、動的なコマンド解釈を行うので動的。
だけど、cout::operator<<() はコンパイル時に解決するので、静的。

間違ってますかね?

正確にはprintfも動的とは言い切れないわけですが...
まぁある程度の範囲で融通効くので、動的と解釈してもいいのかなぁとw

# re: アヒル型 2007/08/30 16:04 uskz

うわ,エスケープもできないのですね.
ほんと何度もすみませんorz

# re: アヒル型 2007/08/30 16:06 επιστημη

uskzさんのコメント:
# 全角空白で置換しますた。
--------------------------

私の提示したものは,あくまで継承階層に依存しない動的多相性であって,静的型付けに対する動的(アヒル)型付けの話で持ってきたのがおかしいような気がしてきました.

あと,やっつけで
class NoSound {};
try_sound(NoSound());
でも動くようにしたので晒しときます.

#include <iostream>
#include <boost/type.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/type_traits/detail/yes_no_type.hpp>

template <typename T>
struct has_sound {
  template <typename U, void (U::*)() const>
  struct aux
  { };

  static boost::type_traits::no_type test(...);

  template <typename U>
  static boost::type_traits::yes_type test(U*, aux<U, &U::sound>* = 0);

  static bool const value
    = sizeof(test((T*)0)) == sizeof(boost::type_traits::yes_type);

  typedef boost::mpl::bool_<value> type;
};

struct unsupported_method
{ };

struct soundable
{
private:
  struct soundable_holder_base
  {
    virtual ~soundable_holder_base()
    { }

    virtual void sound() const = 0;
  };

  template <class T>
  struct soundable_holder :
    soundable_holder_base
  {
    T obj_;

    soundable_holder(T const& obj) :
      obj_(obj)
    { }

    virtual void sound() const
    {
      obj_.sound();
    }
  };

  template <class T>
  struct insoundable_holder :
    soundable_holder_base
  {
    T obj_;

    insoundable_holder(T const& obj) :
      obj_(obj)
    { }

    virtual void sound() const
    {
      throw unsupported();
    }
  };

  soundable_holder_base* soundable_holder_;
  bool is_valid_;
public:
  template <class T>
  soundable(T const& obj) :
    soundable_holder_(
      new typename
        boost::mpl::if_< has_sound<T>,
          soundable_holder<T>,
          insoundable_holder<T>
        >
      ::type(obj)
    )
  {
    is_valid_ = has_sound<T>::value;
  }

  ~soundable()
  {
    delete soundable_holder_;
  }

  void sound() const
  {
    soundable_holder_->sound();
  }

  bool is_valid() const
  {
    return is_valid_;
  }
};

void try_sound(soundable const& object)
{
  if (object.is_valid())
    object.sound();
}

class Duck
{
public:
  void sound() const { std::cout << "くゎっくゎっ\n"; }
};

class Bomb
{
public:
  void sound() const { std::cout << "ちゅどーん\n"; }
};

class NoSound { };

int main()
{
  try_sound(Duck());
  try_sound(Bomb());
  try_sound(NoSound());
}

# re: アヒル型 2007/08/30 18:44 中博俊

void*がDuckそのものじゃないですか

タイトル
名前
URL
コメント