#include <boost/type_traits/is_same.hpp>
#endif
+#include "cast.hpp" // for gintenlib::cast
+
namespace gintenlib
{
// ヘルパ構造体
friend typename enable_if<boost::is_same<U, bool>, bool>::type
operator==( const Derived& lhs, U rhs )
{
- return static_cast<bool>(lhs) == rhs;
+ return cast<bool>(lhs) == rhs;
}
template<typename U>
friend typename enable_if<boost::is_same<U, bool>, bool>::type
operator==( U lhs, const Derived& rhs )
{
- return lhs == static_cast<bool>(rhs);
+ return lhs == cast<bool>(rhs);
}
template<typename U>
friend typename enable_if<boost::is_same<U, bool>, bool>::type
operator!=( const Derived& lhs, U rhs )
{
- return static_cast<bool>(lhs) != rhs;
+ return cast<bool>(lhs) != rhs;
}
template<typename U>
friend typename enable_if<boost::is_same<U, bool>, bool>::type
operator!=( U lhs, const Derived& rhs )
{
- return lhs != static_cast<bool>(rhs);
+ return lhs != cast<bool>(rhs);
}
#else // #ifndef GINTENLIB_BOOL_COMPARABLE_NO_ENABLE_IF
// この場合、 x == 1 のような表現が通ってしまうが仕方ないね
friend bool operator==( const Derived& lhs, bool rhs )
{
- return static_cast<bool>(lhs) == rhs;
+ return cast<bool>(lhs) == rhs;
}
friend bool operator==( bool lhs, const Derived& rhs )
{
- return lhs == static_cast<bool>(rhs);
+ return lhs == cast<bool>(rhs);
}
friend bool operator!=( const Derived& lhs, bool rhs )
{
- return static_cast<bool>(lhs) != rhs;
+ return cast<bool>(lhs) != rhs;
}
friend bool operator!=( bool lhs, const Derived& rhs )
{
- return lhs != static_cast<bool>(rhs);
+ return lhs != cast<bool>(rhs);
}
#endif // #ifndef GINTENLIB_BOOL_COMPARABLE_NO_ENABLE_IF
#include "pointer_facade.hpp"
#include "reference_counter.hpp"
+#include "shared_ptr.hpp" // for to_shared
#include <boost/intrusive_ptr.hpp>
-#include <boost/shared_ptr.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <utility> // for std::pair
};
// shared_ptr に変換
- boost::shared_ptr<T> to_shared() const
+ shared_ptr<T> to_shared() const
{
- return p ? boost::shared_ptr<T>( p, to_shared_helper(count) ) : boost::shared_ptr<T>();
+ return p ? shared_ptr<T>( p, to_shared_helper(count) ) : shared_ptr<T>();
}
- friend boost::shared_ptr<T> to_shared( const this_type& target )
+ friend shared_ptr<T> to_shared( const this_type& target )
{
return target.to_shared();
}
template<typename U> friend class clonable_ptr;
+ // 裏技コンストラクタ
clonable_ptr( const clonable_count& count_, T* p_ )
: p(p_), count(count_) {}
explicit clonable_ptr( const clonable_count::cloned_type& pair )
: p( static_cast<T*>( pair.second ) ), count( pair.first ) {}
+ // pointer casts
template<typename T1, typename T2>
friend clonable_ptr<T1> static_pointer_cast( const clonable_ptr<T2>& src );
template<typename T1, typename T2>
}; // clonable_ptr<T>
- // pointer casts
+ // xxx_pointer_cast
template<typename T, typename S>
inline clonable_ptr<T> static_pointer_cast( const clonable_ptr<S>& src )
{
to_string : 文字列変換
宣言:
- template<typename T>
- std::string to_str( const T& src );
+ // stringstream によって std::string に変換する
template<typename T>
std::string to_string( const T& src );
+
+ // 同じ。ただしより適切な to_string がある場合にはそちらを呼ぶ
+ template<typename T>
+ std::string to_str( const T& src );
機能:
文字列に変換する。
- lexical_castより(たぶん)高速
+ boost::lexical_castより(たぶん)高速
+ std::to_string ができるまでの繋ぎ
*/
return oss.str();
}
+
+ // ADL によって to_string を呼び出す
+ // いわゆる boost::swap 的なもの
template<typename T>
inline std::string to_str( const T& src )
{
- // さらに名前を短縮する
- std::ostringstream oss;
- oss << src;
-
- return oss.str();
+ return to_string( src );
}
} // namespace gintenlib
// boost の単体テストフレームワーク
#include <boost/test/minimal.hpp>
+// ポインタ自身のテスト
+template<typename T>
+void test_pointer( const gintenlib::clonable_ptr<T>& p )
+{
+ // まず get() と get_pointer() のチェック
+ BOOST_CHECK( p.get() == get_pointer(p) );
+
+ // NULL でない場合
+ if( p )
+ {
+ // operator! のチェック
+ BOOST_CHECK( !p == false );
+
+ // operator*, operator-> のチェック
+ BOOST_CHECK( p.get() == &*p );
+ BOOST_CHECK( p.get() == p.operator->() );
+
+ // use_count と unique のチェック
+ BOOST_CHECK( ( p.use_count() == 1 ) == p.unique() );
+ }
+ else
+ {
+ // get() は NULLか
+ BOOST_CHECK( p.get() == 0 );
+ // operator! のチェック
+ BOOST_CHECK( !p );
+
+ // use_count は 0 か?
+ BOOST_CHECK( p.use_count() == 0 );
+ // !unique() か?
+ BOOST_CHECK( !p.unique() );
+
+ }
+}
+
+// 基本的なチェック
template<typename T>
void test1( const gintenlib::clonable_ptr<T>& p0 )
{
- typedef gintenlib::clonable_ptr<T> ptr_type;
+ using gintenlib::clonable_ptr;
+
+ // まず p0 をテスト
+ test_pointer( p0 );
// デフォルト構築
{
- ptr_type p1;
+ clonable_ptr<T> p1;
// NULL にセットされているか?
- BOOST_CHECK( p1.get() == 0 );
+ BOOST_CHECK( !p1 );
+
+ // 他、もろもろはおk?
+ test_pointer( p1 );
}
// コピー
int count = p0.use_count();
// コピーする
- ptr_type p1 = p0;
+ clonable_ptr<T> p1 = p0;
+ // とりあえずテスト
+ test_pointer( p1 );
// アドレスと参照カウントの両面で等しいことを確認
BOOST_CHECK( p0 == p1 );
BOOST_CHECK( p0.use_count() == p1.use_count() );
// リセットのテスト
p1.reset();
BOOST_CHECK( p1 == 0 );
+ // ふたたびテスト
+ test_pointer( p1 );
// この時点で参照カウントは元に戻るはず
BOOST_CHECK( p0.use_count() == count );
// 本題。clone のテスト
{
- ptr_type p1;
+ // まず参照カウントを調べる
+ int count = p0.use_count();
+
+ // clone を作る
+ clonable_ptr<T> p1;
p1 = p0.clone();
+ // とりあえずテスト
+ test_pointer( p1 );
+
+ // clone() しても参照カウントは変わらない
+ BOOST_CHECK( p0.use_count() == count );
- // また、コピーが出来た分、参照カウントは増えているはず
if( p0 )
{
- BOOST_CHECK( p0.get() != p1.get() );
+ // clone で作られたオブジェクトは unique
+ BOOST_CHECK( p1.unique() );
+ // clone したため、別のオブジェクトが格納されてるはず
+ BOOST_CHECK( p0 != p1 );
}
else
{
// unique のときは to_unique() を呼んでも何もしないはず
p1.to_unique();
BOOST_CHECK( p_ == p1.get() );
+ // 念のためテスト
+ test_pointer( p1 );
// 次に p1 にふたたび p0 の値を入れる
p1 = p0;
+ // 念のためテスト
+ test_pointer( p1 );
// 生ポインタの値を更新
p_ = p1.get();
// これにより、NULL であるかユニークじゃないかの状態になった
p1.to_unique();
BOOST_CHECK( p_ == p0.get() );
BOOST_CHECK( !p1 || p_ != p1.get() );
+ // またまたテスト
+ test_pointer( p1 );
}
// おまけで to_shared
int count = p0.use_count();
boost::shared_ptr<T> p1 = to_shared( p0 );
+ // アドレスは一緒
BOOST_CHECK( p0.get() == p1.get() );
+ // カウントは一つ増える
+ BOOST_CHECK( !p0 || p0.use_count() == count+1 );
// shared_ptr がリセットされた場合、ちゃんと参照カウントは減る?
p1.reset();
BOOST_CHECK( p0.use_count() == count );
}
+ // const 関連
+ {
+ // T から const T への変換
+ clonable_ptr<const T> p1 = p0;
+ // 念のためテスト
+ test_pointer( p1 );
+ // アドレスとカウントが等しいことを確認
+ BOOST_CHECK( p0 == p1 );
+ BOOST_CHECK( p0.use_count() == p1.use_count() );
+
+ // const T 型のポインタで reset してみる
+ p1.reset( static_cast<const T*>( new T() ) );
+ // reset 後は当然 unique()
+ BOOST_CHECK( p1 && p1.unique() );
+ // 念のため更にテスト
+ test_pointer( p1 );
+
+ // const T => T の変換( clone すれば可能 )
+ clonable_ptr<T> p2 = p1.clone();
+ // clone しないと無理
+ // clonable_ptr<T> p2 = p1;
+
+ // 念には念を入れてテスト
+ test_pointer( p2 );
+ // clone() 後なので当然 unique
+ BOOST_CHECK( p2 && p2.unique() );
+ BOOST_CHECK( p1 != p2 );
+ }
+
// おわり
}
int test_main( int argc, char* argv[] )
{
test1( gintenlib::clonable_ptr<int>( new int() ) );
- test1( gintenlib::clonable_ptr<int>() );
+ test1( gintenlib::clonable_ptr<int>( static_cast<int*>(0) ) );
return 0;
}
--- /dev/null
+#include "../gintenlib/to_string.hpp"
+
+// boost の単体テストフレームワーク
+#include <boost/test/minimal.hpp>
+
+
+#include <iostream>
+using namespace std;
+
+// テストクラス(単純な例)
+struct hoge
+{
+ // これから to_string が定義される
+ friend ostream& operator<<( ostream& lhs, const hoge& )
+ {
+ return lhs << "hoge";
+ }
+
+};
+
+// テストクラス2
+struct fuga
+{
+ // operator<< の他に
+ friend ostream& operator<<( ostream& lhs, const fuga& )
+ {
+ return lhs << "fuga::operator<<";
+ }
+
+ // friend 関数 to_string を定義するとどうなる?
+ friend string to_string( const fuga& )
+ {
+ return "fuga::to_string";
+ }
+
+};
+
+// テストしてみる
+int test_main( int argc, char* argv[] )
+{
+ using gintenlib::to_string;
+
+ // まず組み込み型
+ BOOST_CHECK( gintenlib::to_string(23) == "23" );
+ BOOST_CHECK( to_string(42) == "42" ); // using してるので無修飾でも使える
+ BOOST_CHECK( gintenlib::to_str(108) == "108" ); // 短縮名
+
+ // ユーザ定義型1
+ hoge h;
+ // 全て operator<< から定義される。簡単
+ BOOST_CHECK( gintenlib::to_string(h) == "hoge" );
+ BOOST_CHECK( to_string(h) == "hoge" );
+ BOOST_CHECK( gintenlib::to_str(h) == "hoge" );
+
+ // ユーザ定義型で、 operator<< の他に to_string が定義されている場合
+ fuga f;
+ // gintenlib::to_string は operator<< から呼ばれる
+ BOOST_CHECK( gintenlib::to_string(f) == "fuga::operator<<" );
+ // 無修飾の to_string は ADL によって fuga に特化したバージョンが呼ばれる
+ BOOST_CHECK( to_string(f) == "fuga::to_string" );
+ // gintenlib::to_str は using 宣言してから無修飾で to_string したのと同じ効果になる
+ BOOST_CHECK( gintenlib::to_str(f) == "fuga::to_string" );
+
+ return 0;
+}