File: udt_example_0.cpp

package info (click to toggle)
boost1.35 1.35.0-5
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 203,856 kB
  • ctags: 337,867
  • sloc: cpp: 938,683; xml: 56,847; ansic: 41,589; python: 18,999; sh: 11,566; makefile: 664; perl: 494; yacc: 456; asm: 353; csh: 6
file content (242 lines) | stat: -rw-r--r-- 7,341 bytes parent folder | download | duplicates (11)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright (C) 2005, Fernando Luis Cacciola Carballal.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
//
#include "boost/config.hpp"
#include "boost/utility.hpp"
#include "boost/limits.hpp"
#include "boost/utility.hpp"

#include<iostream>
#include<iomanip>
#include<string>
#include<cmath>


#include "boost/test/included/test_exec_monitor.hpp"

#include "boost/numeric/conversion/cast.hpp"

using namespace std ;
using namespace boost;
using namespace numeric;

//
// This example illustrates how to add support for user defined types (UDTs)
// to the Boost Numeric Conversion Library.
// It is assumed that you are familiar with the following documentation:
//
//

//
// The minimum requirement is that boost::is_arithmetic<UDT> evaluates to false
// (Otherwise the converter code will try to examine the UDT as a built-in type)
//

//
// Let's start with the simpliest case of an UDT which supports standard conversions
//
struct Double
{
  Double( double v ) : mV(v) {}

  operator double() const { return mV ; }

  double mV ;
} ;

double dv = (numeric_limits<double>::max)() ;
double fv = (numeric_limits<float >::max)() ;
Double Dv(dv);
Double Fv(fv);

void simplest_case()
{
  //
  // conversion_traits<>::udt_builtin_mixture works out of the box as long as boost::is_arithmetic<UDT> yields false
  //
  BOOST_CHECK( (conversion_traits<double,Double>::udt_builtin_mixture::value == udt_to_builtin) ) ;
  BOOST_CHECK( (conversion_traits<Double,double>::udt_builtin_mixture::value == builtin_to_udt) ) ;
  BOOST_CHECK( (conversion_traits<Double,Double>::udt_builtin_mixture::value == udt_to_udt    ) ) ;

  // BY DEFINITION, a conversion from UDT to Builtin is subranged. No attempt is made to actually compare ranges.
  BOOST_CHECK( (conversion_traits<double,Double>::subranged::value) == true  ) ;
  BOOST_CHECK( (conversion_traits<Double,double>::subranged::value) == false ) ;



  //
  // Conversions to/from FLOATING types, if already supported by an UDT
  // are also supported out-of-the-box by converter<> in its default configuration.
  //
  BOOST_CHECK( numeric_cast<double>(Dv) == static_cast<double>(Dv) ) ;
  BOOST_CHECK( numeric_cast<Double>(dv) == static_cast<Double>(dv) ) ;

  BOOST_CHECK( numeric_cast<float> (Dv) == static_cast<float> (Dv) ) ;
  BOOST_CHECK( numeric_cast<Double>(fv) == static_cast<Double>(fv) ) ;


  //
  // Range checking is disabled by default if an UDT is either the source or target of the conversion.
  //
  BOOST_CHECK( (converter<float,double>::out_of_range(dv) == cPosOverflow) );
  BOOST_CHECK( (converter<float,Double>::out_of_range(Dv) == cInRange) );

}

//
// The conversion_traits<> class and therefore the converter<> class looks at
// numeric_limits<UDT>::is_integer/is_signed to generate the proper float_in and sign mixtures.
// In most implementations, is_integer/is_signed are both false for UDTs if there is no explicit specialization for it.
// Therefore, the converter<> will see any UDT for which numeric_limits<> is not specialized as Float AND unsigned.
// Signess is used in the converter<> for range checking, but range checking is disabled by default for UDTs, so,
// normally, signess is mostly irrelevant as far as the library is concerned, except for the numeric_traits<>::sign_mixture
// entry.
// is_integer, however, is relevant in that if the conversion is from a float type to an integer type, the conversion is
// "rounding" and the rounder policies will participate.
// ALL implemented rounder policies require proper definitions for floor(udt) and ceil(udt).
// These names will be searched for using ADL, so, if you need to convert TO integral types from a UDT,
// you need to supply those functions along with the UDT in right namespace (that is, any namespace that allows
// ADL to find them)

// If your UDT doesn't supply floor/ceil, conversions to integer types
// won't compile unless a custom Float2IntRounder is used.

Double floor ( Double v ) { return Double(std::floor(v.mV)) ; }
Double ceil  ( Double v ) { return Double(std::ceil (v.mV)) ; }

void rounding()
{
  BOOST_CHECK( numeric_cast<int>(Dv) == static_cast<int>(Dv) ) ;
}


//
// If your UDT can't or won't provide floor/ceil you can set-up and use your own
// Float2IntRounder policy (though doing this is not always required as shown so far)
//
struct DoubleToInt
{
  static Double nearbyint ( Double const& s ) { return Double(static_cast<int>(s)); }

  typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ;
} ;

void custom_rounding()
{
  typedef converter<int
                   ,Double
                   ,conversion_traits<int,Double>
                   ,void // By default UDT disable range checking so this won't be used
                   ,DoubleToInt
                   >
                   DoubleToIntConverter ;

   BOOST_CHECK( DoubleToIntConverter::convert(Dv) == static_cast<int>(Dv) ) ;
}

//
// In the next Level of complexity, your UDTs might not support conversion operators
//
struct Float
{
  Float( float v ) : mV(v) {}

  float mV ;
} ;

struct Int
{
  Int( int v ) : mV(v) {}

  int mV ;
} ;

typedef conversion_traits<Int,Float> Float2IntTraits ;
typedef conversion_traits<Float,Int> Int2FloatTraits ;

namespace boost { namespace numeric
{
//
// Though static_cast<> won't work with them you can still use numeric_cast<> by specializing
// raw_converter as follows:
//
template<> struct raw_converter<Float2IntTraits>
{
  typedef Float2IntTraits::result_type   result_type   ;
  typedef Float2IntTraits::argument_type argument_type ;

  static result_type low_level_convert ( argument_type s ) { return Int((int)s.mV); }
} ;
template<> struct raw_converter<Int2FloatTraits>
{
  typedef Int2FloatTraits::result_type   result_type   ;
  typedef Int2FloatTraits::argument_type argument_type ;

  static result_type low_level_convert ( argument_type s ) { return Float(s.mV); }
} ;

} }

void custom_raw_converter()
{
  Float f (12.34);
  Int   i (12);
  Float fi(12);

  BOOST_CHECK(numeric_cast<Int>  (f).mV == i .mV ) ;
  BOOST_CHECK(numeric_cast<Float>(i).mV == fi.mV ) ;
}

//
// Alterntively, the custom raw_converter classes can be defined non-instrusively
// (not as specializations) and passed along as policies
//
struct Float2IntRawConverter
{
  static Int low_level_convert ( Float const& s ) { return Int((int)s.mV); }
} ;
struct Int2FloatRawConverter
{
  static Float low_level_convert ( Int const& s ) { return Float(s.mV); }
} ;

void custom_raw_converter2()
{
  Float f (12.34);
  Int   i (12);
  Float fi(12);

  typedef converter<Int
                   ,Float
                   ,Float2IntTraits
                   ,void  // By default UDT disable range checking so this won't be used
                   ,void  // Float2Int Rounder won't be used if Int isn't marked as integer via numeric_limits<>
                   ,Float2IntRawConverter
                   >
                   Float2IntConverter ;

  BOOST_CHECK(Float2IntConverter::convert(f).mV == i .mV ) ;
}

int test_main( int, char* [] )
{
  cout << setprecision( numeric_limits<long double>::digits10 ) ;

  simplest_case();
  rounding();
  custom_rounding();
  custom_raw_converter();
  custom_raw_converter2();

  return 0;
}