Boostの「Function」クラスのドキュメントを見ていて、これに出くわしました。
boost::function<float (int x, int y)> f;
この構文は私にとって非常に混乱していることを認めなければなりません。これはどのようにして合法的なC++になりますか?
ボンネットの下に何かトリックはありますか?この構文はどこかに文書化されていますか?
Boostの「Function」クラスのドキュメントを見ていて、これに出くわしました。
boost::function<float (int x, int y)> f;
この構文は私にとって非常に混乱していることを認めなければなりません。これはどのようにして合法的なC++になりますか?
ボンネットの下に何かトリックはありますか?この構文はどこかに文書化されていますか?
[編集]これは、実際には2つの質問であった、作成者の元の編集されていない質問に対する回答です。
この構文は私にとって非常に混乱していることを認めなければなりません。これはどのようにして合法的なC++になりますか?:)ボンネットの下に何かトリックはありますか?この構文はどこかに文書化されていますか?
これは完全に合法であり、実際にはそれほど複雑ではありません。
template <class T>
class C
{
public:
T* function_pointer;
};
void fn(int x)
{
cout << x << endl;
}
int main(int argc, char** argv)
{
C<void (int x)> c;
c.function_pointer = &fn;
c.function_pointer(123); // outputs x
}
それは基本的に行うことと同じことです:
typedef void Function(int);
C<Function> c;
このタイプは、C ++だけでなく、Cでも同様に適用できます(実際のタイプCはパラメーター化されています)。ここでのテンプレートの魔法は、ここで関数typedefのようなものを取り、戻り値と引数のタイプを検出できるようにすることです。ここでは長すぎることを説明し、boost :: functionは、boostで多くの関数特性メタテンプレートを使用してその情報を取得します。これを学ぶために本当に時間を費やしたい場合は、Boost.TypeTraitsのboost::function_traitsから始まるboostの実装を理解するようにしてください。
しかし、私はあなたの一般的な問題に対処したいと思います。完全に受け入れられるコードの数行を単純化するのに一生懸命努力していると思います。コマンドサブクラスの引数をパラメーター化されたサブクラスコンストラクターに渡すことには何の問題もありません。ここでタイプリストとboost::functionのようなソリューションを使用して、コンパイル時間とコードの複雑さを大幅に増やすことは本当に価値がありますか?
さらに減らしたい場合は、コマンドサブクラスを実行するexecute関数を記述し、それをundoスタックなどに追加します。
typedef boost::shared_ptr<Command> CommandPtr;
void execute(const CommandPtr& cmd)
{
cmd->execute();
// add command to undo stack or whatever else you want to do
}
// The client can simply write something like this:
execute(CommandPtr(new CmdAdd(some_value) );
それをもっと複雑にしようとすることのトレードオフは、それだけの価値がないと本当に思います。Boostの作成者は、多くのプラットフォームやコンパイラの多くの人々が使用する、boost::functionの非常に汎用的なソリューションを作成したいと考えていました。ただし、統合された元にたりシステム全体で異なる署名を持つ関数を実行できるコマンドシステムを一般化しようとはしませんでした(したがって、これらのコマンドの呼び出しが最初に終了した後でも、これらのコマンドの状態を保持し、元に戻して再実行できるようにする必要があります-後続の実行で元の状態データを再指定せずに実行します)。そのためには、継承ベースのアプローチがおそらく最良かつ最も簡単なアプローチです。