C ++ ToStringメンバーファンクションとOstReamオペレーター<<テンプレートを介した統合
質問
私は初心者のC ++開発者であり、質問があります toString
と ostream
テンプレートを介したオペレーターの統合。私はそのようなコードを持っています:
struct MethodCheckerTypes{
typedef unsigned char TrueType;
typedef long FalseType;
};
template<typename T>struct HasToString{
template<typename K>static typename MethodCheckerTypes::TrueType test(decltype(&K::toString));
template<typename> static typename MethodCheckerTypes::FalseType test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(typename MethodCheckerTypes::TrueType);
typedef decltype(test<T>(0)) ValueType;
};
template<typename T, typename K> struct IfDef{};
template<> struct IfDef<typename MethodCheckerTypes::TrueType, ostream&>{
typedef ostream& type;
};
class WithToString{
public:
string toString() const{
return "hello";
}
};
template<typename F, typename CharT, typename Traits> typename IfDef<typename HasToString<F>::ValueType, basic_ostream<CharT, Traits>&>::type operator<<(basic_ostream<CharT, Traits>& out, const F &ref){
out<<ref.toString().c_str();
return out;
}
int main(int argc, char **argv){
WithToString hasToString;
cout<<hasToString<<endl;
return 0;
}
コードはエラーなしで締結されており、アプリケーションは成功しました。そのようなアプローチを使用するのは良いことですか?ブーストの助けなしに実装したかったのです。
解決
実装へのアプローチ operator<<
それ自体が正常です。しかし、あなたが理解していない言語の一部を使用することは悪い習慣です(初心者がそのようなコードを書くことができるとは思いません)。 2つの選択肢があります toString
メンバー関数または過負荷 operator<<(std::ostream&, T)
. 。後者のアプローチでは、使用できます boost::lexical_cast
オブジェクトを文字列に変換します。私に関しては、後者のアプローチはよりC ++ ishです。メンバー関数なしで何かをすることができれば、そうする方が良いでしょう。
他のヒント
@begemothソリューションのオーバーロードストリームオペレーター<<を使用してアプローチを取り、デバッグなど、即時の文字列が必要な場合に便利な「Mixin」クラス「ToString」メソッドを追加しました。
template<typename T>
class ToString
{
public:
std::string toString() const
{
return convertToString(static_cast<const T&>(*this));
}
};
template<typename T>
inline std::string convertToString(const T& value)
{
std::stringstream s;
s << value;
return s.str();
}
その後、OstReamオペレーターがある場合にこのクラスから継承でき、そのクラスでToStringメソッドを提供します。 Boostを使用している場合は、Lexical_castを使用してConvertTostringの実装を置き換えることができます。
template<typename T>
inline std::string convertToString(const T& value)
{
return boost::lexical_cast<std::string>(value);
}
クラスがポインターを介した継承と多型アクセス用に設計されている場合、テンプレートがコンパイル時間に結び付けられているため、上記のソリューションは機能しないため、別のアプローチが必要です。以下のMixinクラスは、仮想メソッドが定義されている上記の「ToString」の代わりに使用できます。次に、テンプレート関数「ConvertTostring」の観点から仮想関数を実装するための便利なマクロが提供されます。これは、上書きする必要があるため、派生クラスの各クラスの本文に追加する必要があり、「この」ポインターは現在のタイプに静的に結び付けられています。
class ToStringVirtual
{
public:
virtual ~ToStringVirtual() {}
virtual std::string toString() const = 0;
};
#define IMPLEMENT_ToStringVirtual public: std::string toString() const override { return convertToString(*this); }