non-intrusive で ad hoc な interface 定義の導入
http://d.hatena.ne.jp/Cryolite/20061213#p2
に関して。
あくまでストリーム入出力とlexical_castに限って、参照を保持するアダプタクラスを作成することを考えます。
次のような使用を想定します。
#includeclass hoge; hoge func(); int main() { hoge x; // パターン1 std::cout << アダプタ(x) << std::endl; // パターン2 std::cout << アダプタ(func()) << std::endl; // パターン3 std::cin >> アダプタ(x); }
パターン1は、出力後も参照先の実体が残っているため寿命の問題もなく、出力なのでconst参照でよいでしょう。
パターン2は、一時オブジェクトを受ける場合です。func()の戻り値の解体は、この行の式の評価の最終段階で行われるので、coutに出力する際の寿命は問題ありません。
パターン1と同様const参照になります。
パターン3は、寿命に関してはパターン1と同じですが、xへの書き込みが発生するため非constの参照が必要です。
パターン3だけ扱う参照の型が違うので素直に実装するとこうなります。
template<class T> struct adaptor { T& ref; explicit adaptor(T& x) : ref(x) { } }; std::ostream& operator<<(std::ostream& os, const adaptor<const hoge>& a) { // ... } std::istream& operator>>(std::istream& is, const adaptor<hoge>& a) { // ... }
ここまで考えてCryoliteさんのところにコメントを書いたわけですが、lexical_castを使うと問題が発生します。
hoge x; std::string s = boost::lexical_cast<std::string>(adaptor<const hoge>(x)); // これはOK x = boost::lexical_cast<adaptor<hoge> >(s).ref; // これは無理
問題は、
です。
やはり入力の場合には参照では駄目で実体が必要になります。
template<class T> struct input_adaptor { T value; }; std::istream& operator>>(std::istream& is, input_adaptor<hoge>& a) { // ... } int main() { std::string s; hoge x = boost::lexical_cast<input_adaptor<hoge> >(s).value; }
最後にvalueからxへのコピーが発生しますが、これはアダプタがなくても同じ事なので、ここでは別問題です。(move semantics要るかも、と思ったのはこの辺でした。)
入力と出力で全然違うクラスを使うのが格好悪いんですが、コスト的にはアダプタなしの状態とほぼ同じになると思います。
パターン3の使用も考慮して、adaptor<hoge>への入力も残しておいて、
template<class T> std::istream& operator>>(std::istream& is, input_adaptor<T>& a) { return is >> adaptor<T>(a.value); }
としておくといいかも知れません。