Skip to content

Commit 41cbc80

Browse files
committed
modified is_ptr to is_pointable, added method traits, added example3
1 parent c06ee0e commit 41cbc80

File tree

4 files changed

+535
-140
lines changed

4 files changed

+535
-140
lines changed

example.cpp

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,12 @@
88
template < typename Ty >
99
struct Sptr : std::shared_ptr< Ty >
1010
{
11-
void func()
12-
{
13-
std::cout << "test\n";
14-
}
1511
Sptr( const Ty& val ) : std::shared_ptr< Ty >( new Ty{ val } ) {}
1612
};
1713

1814
template < typename Ty >
1915
struct Uptr : std::unique_ptr< Ty >
2016
{
21-
void func()
22-
{
23-
std::cout << "test\n";
24-
}
2517
Uptr( const Ty& val ) : std::unique_ptr< Ty >( new Ty{ val } ) {}
2618
};
2719

@@ -30,14 +22,13 @@ int main()
3022
auto check = []( auto&& target )
3123
{
3224
std::cout << typeid( target ).name() << '\n';
33-
std::cout << "is_shared_ptr: " << is_shared_ptr_v< decltype( target ) > << '\n';
34-
std::cout << "is_unique_ptr: " << is_unique_ptr_v< decltype( target ) > << '\n';
35-
std::cout << "is_smart_ptr: " << is_smart_ptr_v< decltype( target ) > << '\n';
36-
std::cout << "is_ptr: " << is_ptr_v< decltype( target ) > << '\n';
37-
std::cout << "is_shared_ptr_soft: " << is_shared_ptr_soft_v< decltype( target ) > << '\n';
38-
std::cout << "is_unique_ptr_soft: " << is_unique_ptr_soft_v< decltype( target ) > << '\n';
39-
std::cout << "is_smart_ptr_soft: " << is_smart_ptr_soft_v< decltype( target ) > << '\n';
40-
std::cout << "is_ptr_soft: " << is_ptr_soft_v< decltype( target ) > << '\n';
25+
std::cout << "is_shared_ptr: " << woon2::is_shared_ptr_v< decltype( target ) > << '\n';
26+
std::cout << "is_unique_ptr: " << woon2::is_unique_ptr_v< decltype( target ) > << '\n';
27+
std::cout << "is_smart_ptr: " << woon2::is_smart_ptr_v< decltype( target ) > << '\n';
28+
std::cout << "is_shared_ptr_soft: " << woon2::is_shared_ptr_soft_v< decltype( target ) > << '\n';
29+
std::cout << "is_unique_ptr_soft: " << woon2::is_unique_ptr_soft_v< decltype( target ) > << '\n';
30+
std::cout << "is_smart_ptr_soft: " << woon2::is_smart_ptr_soft_v< decltype( target ) > << '\n';
31+
std::cout << "is_pointable: " << woon2::is_pointable_v< decltype( target ) > << '\n';
4132
std::cout << "\n\n\n";
4233
};
4334

example2.cpp renamed to example2 - decoupled pointer.cpp

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,84 @@
1+
// ==========================================================================
2+
// Implementation: easily changable pointer for code decoupling
3+
// Just retype the pointer type in line 93.
4+
// ==========================================================================
5+
16
#include <iostream>
27
#include "smart_pointer_type_trait.hpp"
38

49
template < typename Ptr >
5-
auto get_raw_pointer( Ptr& ptr )
10+
decltype( auto ) get_raw_pointer( Ptr&& ptr )
611
{
7-
if constexpr ( std::is_pointer_v< Ptr > ) return ptr;
12+
if constexpr ( std::is_pointer_v< std::decay_t< Ptr > > ) return std::forward< Ptr >( ptr );
813
else return ptr.operator->();
914
}
1015

16+
// a wrapper class of a pointer, for safe compilation.
17+
// if the wrapped class doesn't have required method, it does nothing.
18+
// you can get the original pointer type by using unwrapped ( pointer_impl< Ty, Ptr >::unwrapped ).
1119
template < typename Ty, typename Ptr >
1220
class pointer_impl
1321
{
1422
public:
23+
using unwrapped = Ptr;
24+
1525
void reset( Ty* target = nullptr )
1626
{
17-
if constexpr ( is_smart_ptr_v< Ptr > ) impl.reset( target );
27+
static_assert( woon2::has_reset_v< Ptr > || std::is_pointer_v< Ptr >,
28+
"pointer_impl< Ty, Ptr >::reset(): Ptr doesn't have reset()." );
29+
30+
if constexpr ( woon2::has_reset_v< Ptr > ) impl.reset( target );
1831
else
1932
{
20-
if ( impl ) delete impl;
33+
delete impl;
2134
impl = target;
2235
}
2336
}
2437

25-
void release()
38+
auto release()
2639
{
27-
if constexpr ( std::is_pointer_v< Ptr > ) delete impl;
28-
impl = nullptr;
29-
}
40+
static_assert( woon2::has_release_v< Ptr > || std::is_pointer_v< Ptr > || woon2::is_shared_ptr_soft_v< Ptr >,
41+
"pointer_impl< Ty, Ptr >::release(): Ptr doesn't have release()." );
3042

31-
Ty* get() noexcept { return operator->(); }
32-
const Ty* get() const noexcept { return operator->(); }
43+
if constexpr ( woon2::has_release_v< Ptr > ) return impl.release();
44+
else
45+
{
46+
auto ret = impl;
47+
reset();
48+
return ret;
49+
}
50+
}
3351

3452
decltype( auto ) get_deleter() noexcept
3553
{
36-
static_assert( is_unique_ptr_v< Ptr >, "pointer_impl< Ty, Ptr >::get_deleter(): Ptr was not a unique pointer." );
37-
return impl.get_deleter();
54+
if constexpr ( woon2::has_get_deleter_v< Ptr > ) return impl.get_deleter();
55+
else return nullptr;
3856
}
57+
3958
decltype( auto ) get_deleter() const noexcept
4059
{
41-
static_assert( is_unique_ptr_v< Ptr >, "pointer_impl< Ty, Ptr >::get_deleter(): Ptr was not a unique pointer." );
42-
return impl.get_deleter();
60+
if constexpr ( woon2::has_get_deleter_v< Ptr > ) return impl.get_deleter();
61+
else return nullptr;
62+
}
63+
64+
Ty* get() noexcept
65+
{
66+
return operator->();
67+
}
68+
69+
const Ty* get() const noexcept
70+
{
71+
return operator->();
4372
}
4473

4574
Ty& operator*() noexcept { return *impl; }
4675
const Ty& operator*() const noexcept { return *impl; }
47-
Ty* operator->() noexcept { return get_raw_pointerr( impl ); }
76+
Ty* operator->() noexcept { return get_raw_pointer( impl ); }
4877
const Ty* operator->() const noexcept { return get_raw_pointer( impl ); }
4978
operator bool() const noexcept { return static_cast< bool >( get_raw_pointer( impl ) ); }
5079

5180
// special member functions
5281
pointer_impl( Ty* impl = nullptr ) : impl{ impl } {}
53-
~pointer_impl() { release(); }
5482

5583
private:
5684
Ptr impl;
@@ -59,12 +87,12 @@ class pointer_impl
5987
// ======================================================
6088
// ******************************************************
6189
// Decoupling by using keyword.
62-
// memory allocation policy has only-one dependancy, this code.
90+
// Memory allocation policy has the only dependancy on this code.
6391
// ======================================================
6492
template < typename Ty >
6593
using pointer = pointer_impl< Ty, std::unique_ptr< Ty > >; // can change to diffrent pointer
66-
// If you add more pointer object, ( and similar type trait )
67-
// can also change to the pointer object.
94+
// if you add more pointer class,
95+
// you can also change to the pointer class.
6896
// ******************************************************
6997
// ======================================================
7098

@@ -89,8 +117,8 @@ struct INT
89117

90118
return *this;
91119
}
92-
INT( INT&& other ) : impl{ other.impl } { std::cout << "INT move constructor called\n"; }
93-
INT& operator=( INT&& other )
120+
INT( INT&& other ) noexcept : impl{ other.impl } { std::cout << "INT move constructor called\n"; }
121+
INT& operator=( INT&& other ) noexcept
94122
{
95123
if ( this != &other )
96124
{
@@ -112,7 +140,7 @@ int main()
112140
std::cout << "========================================\n\n\n";
113141

114142
std::cout << "get_deleter() call =====================\n";
115-
std::cout << typeid( a.get_deleter() ).name() << '\n'; // only can executed with unique pointer
143+
std::cout << typeid( a.get_deleter() ).name() << '\n';
116144
std::cout << "========================================\n\n\n";
117145

118146
std::cout << "print value ============================\n";
@@ -128,4 +156,9 @@ int main()
128156
std::cout << "========================================\n\n\n";
129157

130158
std::cout << "must call destructor ===================\n";
159+
if constexpr ( std::is_pointer_v< decltype( a )::unwrapped > )
160+
{
161+
std::cout << "cause unwrapped pointer type was a raw pointer, called release().\n";
162+
a.release();
163+
}
131164
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// ==========================================================================
2+
// Implementation: added new pointer class
3+
// this is an example of smart_pointer_type_trait.hpp's additional type trait guide.
4+
// ==========================================================================
5+
6+
#include <iostream>
7+
#include "smart_pointer_type_trait.hpp"
8+
9+
template< typename Ty >
10+
class value_pointer
11+
{
12+
public:
13+
// methods
14+
void reset( const Ty& val = Ty{} )
15+
{
16+
if ( !raw_ptr ) raw_ptr = new Ty{ val };
17+
else *raw_ptr = val;
18+
}
19+
20+
void reset( Ty&& val )
21+
{
22+
if ( !raw_ptr ) raw_ptr = new Ty{ std::move( val ) };
23+
else *raw_ptr = std::move_if_noexcept( val );
24+
}
25+
26+
void release()
27+
{
28+
delete raw_ptr;
29+
raw_ptr = nullptr;
30+
}
31+
32+
void swap( value_pointer& right )
33+
{
34+
if ( !raw_ptr ) throw std::exception{ "value_pointer< Ty >::swap(): raw_ptr was null pointer." };
35+
if ( !right.raw_ptr ) throw std::exception{ "value_pointer< Ty >::swap(): invalid argument( right was null pointer. )" };
36+
37+
auto temp = std::move_if_noexcept( *right.raw_ptr );
38+
*right.raw_ptr = std::move_if_noexcept( *raw_ptr );
39+
*raw_ptr = std::move_if_noexcept( temp );
40+
}
41+
42+
// operators
43+
Ty& operator*() { return *raw_ptr; }
44+
const Ty& operator*() const { return *raw_ptr; }
45+
Ty* operator->() { return raw_ptr; }
46+
const Ty* operator->() const { return raw_ptr; }
47+
48+
// special member functions
49+
value_pointer( const Ty& val ) : raw_ptr{ new Ty{ val } } {}
50+
value_pointer( Ty&& val ) : raw_ptr{ new Ty{ std::move( val ) } } {}
51+
value_pointer( const value_pointer& other ) : raw_ptr{ new Ty{ *other } } {}
52+
value_pointer& operator=( const value_pointer& other )
53+
{
54+
if ( this != &other ) reset( *other );
55+
return *this;
56+
}
57+
value_pointer( value_pointer&& other ) noexcept : raw_ptr{ new Ty{ std::move( *other ) } } {}
58+
value_pointer& operator=( value_pointer&& other ) noexcept
59+
{
60+
if ( this != &other ) reset( std::move( *other ) );
61+
return *this;
62+
}
63+
~value_pointer() { if ( raw_ptr ) delete raw_ptr; }
64+
65+
private:
66+
Ty* raw_ptr;
67+
};
68+
69+
template < typename Ty >
70+
struct Vptr : value_pointer< Ty > {};
71+
72+
// =====================================================================
73+
// *********************************************************************
74+
// new type trait ( value_ptr )
75+
// just retyped the pointer's name.
76+
// *********************************************************************
77+
// =====================================================================
78+
79+
namespace woon2
80+
{
81+
namespace detail
82+
{
83+
template < typename T >
84+
struct is_value_pointer_impl : std::false_type {};
85+
86+
template < typename T >
87+
struct is_value_pointer_impl< value_pointer< T > > : std::true_type {};
88+
89+
template < typename T >
90+
std::true_type is_value_pointer_soft_impl( value_pointer< T >* );
91+
std::false_type is_value_pointer_soft_impl( ... );
92+
}
93+
94+
template < typename T >
95+
using is_value_pointer = detail::is_value_pointer_impl< detail::remove_cvr_t< T > >;
96+
97+
template < typename T >
98+
constexpr bool is_value_pointer_v = is_value_pointer< T >::value;
99+
100+
template < typename T >
101+
using is_value_pointer_soft = decltype( detail::is_value_pointer_soft_impl( std::declval< detail::remove_cvr_t< T >* >() ) );
102+
103+
template < typename T >
104+
constexpr bool is_value_pointer_soft_v = is_value_pointer_soft< T >::value;
105+
}
106+
107+
// =====================================================================
108+
109+
struct INT
110+
{
111+
INT( int impl = 0 ) : impl{ impl } { std::cout << "INT constructor called\n"; }
112+
~INT() { std::cout << "INT destructor called\n"; }
113+
INT( const INT& other ) : impl{ other.impl } { std::cout << "INT copy constructor called\n"; }
114+
INT& operator=( const INT& other )
115+
{
116+
if ( this != &other )
117+
{
118+
std::cout << "INT copy allocator called\n";
119+
impl = other.impl;
120+
}
121+
122+
return *this;
123+
}
124+
INT( INT&& other ) noexcept : impl{ other.impl } { std::cout << "INT move constructor called\n"; }
125+
INT& operator=( INT&& other ) noexcept
126+
{
127+
if ( this != &other )
128+
{
129+
std::cout << "INT move allocator called\n";
130+
impl = other.impl;
131+
}
132+
133+
return *this;
134+
}
135+
operator int() { return impl; }
136+
137+
int impl;
138+
};
139+
140+
int main()
141+
{
142+
// test type traits ==============================================
143+
static_assert( woon2::is_pointable_v< value_pointer< int > >, "is_pointable trait doesn't work." );
144+
static_assert( woon2::is_value_pointer_v< value_pointer< int > >, "is_value_pointer trait doesn't work." );
145+
static_assert( woon2::is_value_pointer_soft_v< Vptr< int > >, "is_value_pointer_soft trait doesn't work." );
146+
static_assert( !woon2::has_get_deleter_v< value_pointer< int > >, "has_get_deleter trait doesn't work." );
147+
static_assert( woon2::has_release_v< value_pointer< int > >, "has_release trait doesn't work." );
148+
static_assert( woon2::has_swap_v< value_pointer< int > >, "has_swap trait doesn't work." );
149+
static_assert( woon2::has_reset_v< value_pointer< int > >, "has_reset trait doesn't work." );
150+
// ===============================================================
151+
152+
std::cout << "====================================================\n";
153+
std::cout << "value_pointer test\n";
154+
std::cout << "====================================================\n\n\n";
155+
156+
try {
157+
std::cout << "construct a ========================================\n";
158+
value_pointer< INT > a{ 3 };
159+
std::cout << "====================================================\n\n\n";
160+
161+
std::cout << "construct b ========================================\n";
162+
value_pointer< INT > b{ 4 };
163+
std::cout << "====================================================\n\n\n";
164+
165+
std::cout << "print values =======================================\n";
166+
std::cout << "a: " << *a << ", b: " << *b << '\n';
167+
std::cout << "====================================================\n\n\n";
168+
169+
std::cout << "swap a, b ==========================================\n";
170+
a.swap( b );
171+
std::cout << "====================================================\n\n\n";
172+
173+
std::cout << "print values =======================================\n";
174+
std::cout << "a: " << *a << ", b: " << *b << '\n';
175+
std::cout << "====================================================\n\n\n";
176+
177+
std::cout << "release a ==========================================\n";
178+
a.release();
179+
std::cout << "====================================================\n\n\n";
180+
181+
std::cout << "reset a with b =====================================\n";
182+
a.reset( *b );
183+
std::cout << "====================================================\n\n\n";
184+
185+
std::cout << "print values =======================================\n";
186+
std::cout << "a: " << *a << ", b: " << *b << '\n';
187+
std::cout << "====================================================\n\n\n";
188+
189+
std::cout << "must call destructors ==============================\n";
190+
}
191+
catch ( const std::exception& e )
192+
{
193+
std::cout << e.what();
194+
exit( -1 );
195+
}
196+
}

0 commit comments

Comments
 (0)