エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

メソッドホルダ・分析篇

昨日のエントリではかなりダメダメな感じになったのですが、「じゃぁBoost Libraryではどうやっているのか?」が知りたくなり、昨日のエントリの最後にBoost Libraryで書いたコードをプリプロセッサに通した結果を表示させてみた。
なんと、こんな感じだった!

// (長過ぎるので省略)


引数なしの関数から引数を9つとる関数までの定義がズラっと。それも普通の関数の場合、メンバ関数の場合、メンバ関数constが指定されている場合、etc...。実際にはマクロを使って展開しているのだと思いますが、ここまでやっているとは思いませんでした。
安易に立ち向かおうとした自分が浅はかだった…。


それはそれとして。プリプロセッサを通して展開されたコードを見ていて気になったことが一つ。戻り値がある場合とない場合の区別がされていない。区別しなくていいんだろうか?


つまりこういうことです。
次のようなクラステンプレートがあった場合。

// 型がARG1の引数一つ、戻り値の型がRESULTの関数のポインタを保存するクラス
template<typename RESULT, typename ARG1>
struct Function
{
    Function(RESULT(*f)(ARG1)) : f_(f) {}

    RESULT operator () (ARG1 arg1)
    {
        // 関数の呼び出し
        return f_(arg1);
    }

    RESULT (*f_)(ARG1);
};


このようなクラステンプレートがあった場合、戻り値がない(戻り値の型がvoidの)場合、関数の呼び出し方を変える必要があるのでは?次のように特殊化してやる必要があるのではないか?ということです。

// 型がARG1の引数一つ、戻り値の型がvoidの関数のポインタを保存するクラス
template<typename ARG1>
struct Function<void, ARG1>
{
    Function(void(*f)(ARG1)) : f_(f) {}

    void operator () (ARG1 arg1)
    {
        // 関数の呼び出し
        f_(arg1); // returnしない
    }

    void (*f_)(ARG1);
};


不審に思って検索してみたら、ありました。JIS X3014*1の79ページに、戻り値がvoidの関数でreturn文を書く場合、値がviodとなる式を書くことができる、とあります。
つまり、次のようなコードがOKなわけです。

void foo()
{
    // do something
    return (void)(0);
}


return文に書く式は関数でもいいので、次のようなコードもOKになります。

void bar()
{
    // do something
}

void baz()
{
    return bar(); // 戻り値がvoidの関数をreturnする
}


結果として。上で書いたような、戻り値がvoidの場合に特殊化する必要がなくなります。


この辺りの仕様がC言語でどうなっていたかはわからないのですが、このvoidを返すのOKというこの仕様、こういう場合のための仕様のような気がします。


なんとなくバッドノウハウの香り。

*1:直接にリンクが張れないようなので、参照する場合はここから「x3014」と入力して検索してください