これについての私の見解: 見つけたメタ関数をそのまま使用できます。うまく機能します。それが機能している理由を簡単に説明しましょう。
sizeof
実際には式を評価しません。その型を推測し、その型のサイズを返します。型のサイズは実装で定義されており、それらについて多くを想定することはできませんが、それはわかっているsizeof(char) != sizeof(char[2])
ので、これらの型を使用してテストします。
型を使用して名前空間レベルでストリーム演算子を定義します。これは、ご想像のany_t
とおり、任意の型を受け入れ、何かを返すようにします (型でない限り、実際にはどの型かは重要ではありませんostream &
)。これは、型にストリーム演算子が定義されていない場合にフォールバックするものです。クラス自体で 2 つの関数を定義します。1 つostream &
はストリーム演算子が定義されている場合の結果となる を受け取り、もう 1 つはフォールバック関数用に定義した戻り値の型を受け取ります。
sizeof(test(s << c))
これで、どちらが式を評価せず、戻り値の型のみを決定し、そのサイズを返すかをテストできます。
これで、これがどのように機能するかを理解できたので、あとはこれをアプリケーションに埋め込むだけです。これを行うにはいくつかの方法があります。C++11より前でも機能する1つの方法は、ファンクターを使用することです。
template <bool, typename T>
struct to_string_functor
{
std::string operator()(T const & t) const
{
std::stringstream ss;
ss << t;
return ss.str();
}
};
template <typename T>
struct to_string_functor<false, T>
{
std::string operator()(T const &) const
{
return typeid(T).name();
}
};
template <typename T>
struct foo
{
std::string to_string() const
{
return to_string_functor<
has_insertion_operator<T>::value, T
>()(m_Value);
}
/* ... */
};
これを行う方法は他にもあります。別の方法はenable_if
、C++11 が利用できる場合です (これを行うには、部分的に特殊化された関数が必要になる可能性があります)。この問題に関するこの優れたブログ投稿を読むことをお勧めします。
ただし、この単純なケースでは、ファンクターが行うべきだと私は考えています。