概要
C++のSFINAEを利用して、ある型が入力ストリーム、出力ストリームに対応しているかどうかを判断するメタ関数を作成しました。
この記事に載せているコードはC++11に対応したコンパイラで動きます。
ソースコード
#include <iostream>
#include <type_traits>
#include <string> //MSVCではこれが必要
//入力ストリームに対応しているかどうかを判断するメタ関数
template<typename T, typename U = void>
struct is_istream_compatible : public std::false_type{};
template<typename T>
struct is_istream_compatible<T, decltype(std::declval<std::istream&>() >> std::declval<T&>(),std::declval<void>())> : public std::true_type{};
//出力ストリームに対応しているかどうかを判断するメタ関数
template<typename T, typename U = void>
struct is_ostream_compatible : public std::false_type{};
template<typename T>
struct is_ostream_compatible<T, decltype(std::declval<std::ostream&>() << std::declval<T&>(),std::declval<void>())> : public std::true_type{};
解説
is_istream_compatibleは入力ストリームに対応しているかどうかを判断するためのメタ関数です。
このメタ関数では、部分特殊化されたクラステンプレートでdecltypeを用いてstd::istreamと型Tに対応する>>演算子の戻り値型を取得しようとしています。
この時、対応する>>演算子が定義されている場合は部分特殊化された、std::true_typeを継承したクラステンプレートが実体化されます。
また、定義されていない場合はSFINAEにより部分特殊化されたクラステンプレートが省かれ、std::false_typeを継承したクラステンプレートが実体化されます。
これによりoperator>>(std::istream&, T&)が定義されているかどうか、つまり入力ストリームに対応しているかどうかを判断しています。
is_ostream_compatibleは出力ストリームに対応しているかどうかを判断するためのメタ関数ですが、is_istream_compatibleと仕組みは同じです。
#動作例
#include "is_iostream_compatible.hpp"
//入出力ストリームに対応していないクラス
struct NotIOStreamCompatible{};
int main() {
//std::stringとNotIOStreamCompatibleが入力ストリームに対応しているか確認
std::cout << is_istream_compatible<std::string>::value << is_istream_compatible<NotIOStreamCompatible>::value << std::endl;
//intとNotIOStreamCompatibleが出力ストリームに対応しているか確認
std::cout << is_ostream_compatible<int>::value << is_ostream_compatible<NotIOStreamCompatible>::value << std::endl;
return 0;
}
10
10
intとstd::stringは入出力ストリームに対応しておりNotIOStreamCompatibleは対応していないので、結果は正しいことがわかります。
今回は直接用いる例を書きましたが、今回作成したメタ関数は他のメタ関数を作ったりテンプレートメタプログラミングを行ったりするときに役に立つと思います。