1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
#include <iostream>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <new>
namespace utility
{
struct int_or_str
{
struct type_error : public virtual std::domain_error { type_error() : std::domain_error("wrong type") {} };
using string = std::string ;
operator int&() { if( type == INT ) return i ; else throw type_error() ; }
operator int() const { if( type == INT ) return i ; else throw type_error() ; }
operator string&() { if( type == STR ) return s ; else throw type_error() ; }
operator string() const { if( type == STR ) return s ; else throw type_error() ; }
int_or_str() = default ;
int_or_str( int v ) : type(INT), i(v) {}
int_or_str( const string& v ) : type(STR), s(v) {}
int_or_str( string&& v ) : type(STR), s( std::move(v) ) {}
int_or_str( const char* v ) : type(STR), s(v) {}
int_or_str( const int_or_str& that ) : type(that.type)
{ if(type==INT) i = that.i ; else new ( std::addressof(s) ) string(that.s) ; }
int_or_str( int_or_str&& that ) : type(that.type)
{ if(type==INT) i = that.i ; else new ( std::addressof(s) ) string( std::move(that.s) ) ; }
// dual-role assignment operator: both copy assignment and move assignment
// pass rhs by value: lvalues are copied, and rvalues are moved
int_or_str& operator= ( int_or_str that ) { swap(that) ; return *this ; }
~int_or_str() { if( type == STR ) s.~string() ; }
void swap( int_or_str& that )
{
using std::swap ;
if( type == INT )
{
if( that.type == INT ) swap( i, that.i ) ;
else
{
const int saved_i = i ;
new ( std::addressof(s) ) string( std::move(that.s) ) ;
that.s.~string() ;
that.i = saved_i ;
}
}
else // type == STR
{
if( that.type == STR ) swap( s, that.s ) ;
else
{
const int saved_i = that.i ;
new ( std::addressof(that.s) ) string( std::move(s) ) ;
s.~string() ;
i = saved_i ;
}
}
swap( type, that.type ) ;
}
private:
enum type_tag { INT, STR } ;
type_tag type = INT ;
union
{
int i = 0 ;
string s ;
};
friend std::ostream& operator<< ( std::ostream& stm, const int_or_str& x )
{ if( x.type == int_or_str::INT ) return stm << x.i ; else return stm << x.s ; }
friend bool operator== ( const int_or_str& a, const int_or_str& b )
{
if( a.type != b.type ) return false ;
else return a.type == int_or_str::INT ? ( a.i == b.i ) : ( a.s == b.s ) ;
}
friend bool operator!= ( const int_or_str& a, const int_or_str& b ) { return !(a==b) ; }
// etc.
};
void swap( int_or_str& a, int_or_str& b ) { a.swap(b) ; }
}
int main()
{
utility::int_or_str x = 45 ;
utility::int_or_str y = "hello world" ;
std::cout << x << ' ' << y << '\n' ;
x = "hello again" ;
y = 92 ;
std::cout << x << ' ' << y << '\n' ;
std::string s = x ; int& ri = y ; std::cout << s << ' ' << ri << '\n' ;
ri += 123 ;
std::cout << x << ' ' << y << '\n' ;
using std::swap ;
swap( x, y ) ;
std::cout << x << ' ' << y << '\n' ;
}
|