みなさん、こんにちわ。アメブロで主にストレージに関して
いろいろ書いていたんですが、どうもやはりコードを載せるには向いていない
感じがしたのでこちらにいろいろと移転してみました^^
さて、最近Cocos2d-xが流行っているので、その記事がたくさん投稿されているので、結構助かっているのですが、そのインターフェースであるC++言語があまりにも難しく扱いずらい為なかなか突っ込んだ事が書かれている記事が少ないことに気づき、僕の知識の範囲でC++のニッチだが、その界隈では有名なテクニックだとかを紹介していこうかと思います。今日は手始めにSFIANE機構っていうのを紹介します。
SFIANEってなに?
SFIANE(Substitution Failure Is Not An Error)っていう機構がC++にあります。直訳すると置き換えの失敗はエラーではないって意味です。手っ取り早くコードを使って説明すると
#include <iostream>
using namespace std;
struct A {
typedef int int_A;
};
template <class T>
void show(typename T::int_A) {
cout << "クラステンプレートを使ってインスタンス化" << endl;
};
template <class T>
void show(...) {
cout << "それ以外のインスタンス化" << endl;
};
int main() {
show<int>(0); //-> "それ以外のインスタンス化"
show<int>("hoge"); //-> "それ以外のインスタンス化"
show<A>(0); //-> "クラステンプレートを使ってインスタンス化"
show<A>("hoge"); //-> "それ以外のインスタンス化"
}
実はとっても変な事がここでは起きています。引数に関しての関数のオーバーロードであれば、単純に引数が合致してそうなのが呼ばれますが、これに関しては型引数も含めてうまく合致しているものが検出でき、それ以外はオーバーロード候補からはずしています。
つまり、言い換えれば、型引数と関数の引数によって実体化自体が分岐できるということになります。これだけだと何に役に立つのかよくわかりませんが、これを利用すると、想定した機能が実装されたクラスが型引数に渡されたかどうかを検出できます。さらに、想定した型が来なかった場合、例外的に処理できます。
template <class T>
struct is_void {
static const bool value = false;
}
template <>
struct is_void<void> {
static const bool value = true;
}
#include <iostream>
using namespace std;
int main() {
cout << is_void<void>::value << endl; // -> true
cout << is_void<int>::value << endl; // -> false
}
これは 型がvoidで実体化される時だけ例外的な処理を行っている例です。
発展すると、decltypeと組み合わせて指定した関数がある場合はその関数を呼び、そうでない場合はコンパイル時に警告を出して、似た挙動の関数を呼ぶとかできそうです。