mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
580 lines
No EOL
18 KiB
C++
580 lines
No EOL
18 KiB
C++
topic "U++ Core value types tutorial";
|
|
[2 $$0,0#00000000000000000000000000000000:Default]
|
|
[l288;i1120;a17;O9;~~~.1408;2 $$1,0#10431211400427159095818037425705:param]
|
|
[a83;*R6 $$2,5#31310162474203024125188417583966:caption]
|
|
[H4;b83;*4 $$3,5#07864147445237544204411237157677:title]
|
|
[i288;O9;C2 $$4,6#40027414424643823182269349404212:item]
|
|
[b42;a42;ph2 $$5,5#45413000475342174754091244180557:text]
|
|
[l288;b17;a17;2 $$6,6#27521748481378242620020725143825:desc]
|
|
[l321;t246;C@5;1 $$7,7#20902679421464641399138805415013:code]
|
|
[b2503;2 $$8,0#65142375456100023862071332075487:separator]
|
|
[*@(0.0.255)2 $$9,0#83433469410354161042741608181528:base]
|
|
[t4167;C2 $$10,0#37138531426314131251341829483380:class]
|
|
[l288;a17;*1 $$11,11#70004532496200323422659154056402:requirement]
|
|
[i417;b42;a42;O9;~~~.416;2 $$12,12#10566046415157235020018451313112:tparam]
|
|
[b167;C2 $$13,13#92430459443460461911108080531343:item1]
|
|
[i288;a42;O9;C2 $$14,14#77422149456609303542238260500223:item2]
|
|
[*@2$(0.128.128)2 $$15,15#34511555403152284025741354420178:NewsDate]
|
|
[l321;*C$7;2 $$16,0#03451589433145915344929335295360:result]
|
|
[l321;b83;a83;*C$7;2 $$17,17#07531550463529505371228428965313:result`-line]
|
|
[l160;t4167;*C+117 $$18,5#88603949442205825958800053222425:package`-title]
|
|
[2 $$19,0#53580023442335529039900623488521:gap]
|
|
[t4167;C2 $$20,20#70211524482531209251820423858195:class`-nested]
|
|
[b50;2 $$21,21#03324558446220344731010354752573:Par]
|
|
[{_}%EN-US
|
|
[s2; U`+`+ Core value types tutorial&]
|
|
[s3; 1. String&]
|
|
[s5; String is a value type useful for storing text or binary data.
|
|
Content of String can be also obtained in form zero terminated
|
|
const char `*ptr (valid till the next mutating operation only.&]
|
|
[s5; You can assign a C string literal to String&]
|
|
[s5; &]
|
|
[s7; String a;&]
|
|
[s7; a `= `"Hello`";&]
|
|
[s7; &]
|
|
[s16; a `= Hello&]
|
|
[s7; &]
|
|
[s5; &]
|
|
[s5; concatenate with another String or literal&]
|
|
[s5; &]
|
|
[s7; a `= a `+ `" world`";&]
|
|
[s7; &]
|
|
[s16; a `= Hello world&]
|
|
[s7; &]
|
|
[s5; &]
|
|
[s5; or single character or specified number of characters from another
|
|
String or literal&]
|
|
[s5; &]
|
|
[s7; a.Cat(`'!`');&]
|
|
[s7; &]
|
|
[s16; a `= Hello world!&]
|
|
[s7; &]
|
|
[s7; a.Cat(`"ABCDEFGHIJKLM`", 3);&]
|
|
[s7; &]
|
|
[s16; a `= Hello world!ABC&]
|
|
[s7; &]
|
|
[s5; &]
|
|
[s5; Clear method empties the String&]
|
|
[s5; &]
|
|
[s7; a.Clear();&]
|
|
[s5; &]
|
|
[s5; You can use operator<< to append to existing String. Note that
|
|
this is more efficient form than operator`+ as String is not
|
|
required to be assigned a temporary. Also, U`+`+ provides extensible
|
|
framework for converting values to String&]
|
|
[s5; &]
|
|
[s7; for(int i `= 0; i < 10; i`+`+)&]
|
|
[s7; -|a << i << `", `";&]
|
|
[s7; &]
|
|
[s16; a `= 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, &]
|
|
[s5; &]
|
|
[s5; Sometimes is is useful to use operator<< to produce a temporary
|
|
String value (e.g. as real argument to function call).&]
|
|
[s5; &]
|
|
[s7; String().Cat() << `"Number is `" << 123 << `".`"&]
|
|
[s5; &]
|
|
[s5; Note: This strange special Cat method is needed because C`+`+
|
|
does not allow non`-cont references to temporary objects.&]
|
|
[s5; &]
|
|
[s16; Number is 123.&]
|
|
[s5; &]
|
|
[s5; String provides methods for obtaining character count, inserting
|
|
characters into String or removing them&]
|
|
[s5; &]
|
|
[s7; a `= `"0123456789`";&]
|
|
[s7; &]
|
|
[s16; a.GetLength() `= 10&]
|
|
[s7; &]
|
|
[s7; a.Insert(6, `"<inserted>`");&]
|
|
[s7; &]
|
|
[s16; a `= 012345<inserted>6789&]
|
|
[s7; &]
|
|
[s7; a.Remove(2, 2);&]
|
|
[s7; &]
|
|
[s16; a `= 0145<inserted>6789&]
|
|
[s7; &]
|
|
[s5; &]
|
|
[s5; as well as a couple of searching and comparing methods&]
|
|
[s5; &]
|
|
[s7; a.Find(`'e`')&]
|
|
[s7; &]
|
|
[s16; a.Find(`'e`') `= 8&]
|
|
[s7; &]
|
|
[s7; a.ReverseFind(`'e`')&]
|
|
[s7; &]
|
|
[s16; a.ReverseFind(`'e`') `= 11&]
|
|
[s16; &]
|
|
[s7; a.StartsWith(`"ABC`")&]
|
|
[s7; &]
|
|
[s16; a.StartsWith(`"ABC`") `= false&]
|
|
[s7; &]
|
|
[s7; a.EndsWith(`"KLM`")&]
|
|
[s7; &]
|
|
[s16; a.EndsWith(`"KLM`") `= false&]
|
|
[s7; &]
|
|
[s7; a.Find(`"ted`")&]
|
|
[s7; &]
|
|
[s16; a.Find(`"ted`") `= 10&]
|
|
[s5; &]
|
|
[s5; You can get slice of String using Mid method; with single parameter
|
|
it provides slice to the end of String&]
|
|
[s5; &]
|
|
[s7; a.Mid(3, 3)&]
|
|
[s7; &]
|
|
[s16; a.Mid(3, 3) `= 5<i&]
|
|
[s7; &]
|
|
[s7; a.Mid(3)&]
|
|
[s7; &]
|
|
[s16; a.Mid(3) `= 5<inserted>6789&]
|
|
[s5; &]
|
|
[s5; You can also decrease the length of String using Trim&]
|
|
[s5; &]
|
|
[s7; a.Trim(4);&]
|
|
[s7; &]
|
|
[s16; a `= 0145&]
|
|
[s5; &]
|
|
[s5; You can obtain int values of individual characters using operator`[`]&]
|
|
[s5; &]
|
|
[s7; a`[0`]&]
|
|
[s7; &]
|
|
[s16; a`[0`] `= 48&]
|
|
[s5; &]
|
|
[s5; or the value of first character using operator`* (note that
|
|
if GetLengt() `=`= 0, this will return zero terminator)&]
|
|
[s5; &]
|
|
[s7; -|DUMP(`*a);&]
|
|
[s7; &]
|
|
[s16; `*a `= 48&]
|
|
[s5; &]
|
|
[s3; 2. StringBuffer&]
|
|
[s5; If you need a direct write access to String`'s C`-string character
|
|
buffer, you can use complementary StringBuffer class. One of
|
|
reasons to do so is when you have to deal with some C`-API functions&]
|
|
[s5; &]
|
|
[s7; void CApiFunction(char `*c)&]
|
|
[s7; `{&]
|
|
[s7; -|strcpy(c, `"Hello`");&]
|
|
[s7; `}&]
|
|
[s7; &]
|
|
[s7; ..........&]
|
|
[s7; &]
|
|
[s7; [* -|StringBuffer] b;&]
|
|
[s7; -|b.[* SetLength](200);&]
|
|
[s7; -|CApiFunction(b);&]
|
|
[s7; -|b.[* Strlen]();&]
|
|
[s7; -|String x [* `=] b;&]
|
|
[s7; &]
|
|
[s16; x `= Hello&]
|
|
[s5; &]
|
|
[s5; In this case, SetLength creates a C array of 200 characters.
|
|
You can then call C`-API function. Later you set the real length
|
|
using Strlen `- this function performs strlen of buffer and sets
|
|
the length accordingly. Later you simply assign the StringBuffer
|
|
to String. Note that for performance reasons, this operation
|
|
clears the StringBuffer content (operation is fast and does not
|
|
depend on the number of characters).&]
|
|
[s5; Another usage scenario of StringBuffer is about altering existing
|
|
String&]
|
|
[s5; &]
|
|
[s7; -|b `= x;&]
|
|
[s7; -|b`[1`] `= `'a`';&]
|
|
[s7; -|x `= b;&]
|
|
[s7; &]
|
|
[s16; x `= Hallo&]
|
|
[s5; &]
|
|
[s5; Similar to assigning StringBuffer to String, assigning String
|
|
to StringBuffer clears the source String.&]
|
|
[s5; StringBuffer also provides appending operations:&]
|
|
[s7; -|b `= x;&]
|
|
[s7; -|b.Cat(`'!`');&]
|
|
[s7; -|x `= b;&]
|
|
[s7; &]
|
|
[s16; x `= Hallo!&]
|
|
[s16; &]
|
|
[s5; Note that sometimes when creating some String from a lot of
|
|
single characters, using StringBuffer for the operation is slightly
|
|
faster then using String directly.&]
|
|
[s5; &]
|
|
[s3; 3. WString&]
|
|
[s5; String works with 8 bit characters. For 16`-bit character encoding
|
|
use WString. Both classes are closely related and share most
|
|
of interface methods. U`+`+ also provides conversions between
|
|
String and WString and you can also use 8 bit string literals
|
|
with WString. Conversion is ruled by current [*/ default character
|
|
set][/ . ]Default value of default character set is CHARSET`_UTF8.&]
|
|
[s5; &]
|
|
[s7; -|WString x `= `"characters 280`-300: `";&]
|
|
[s7; -|for(int i `= 280; i < 300; i`+`+)&]
|
|
[s7; -|-|x.Cat(i);&]
|
|
[s7; &]
|
|
[s16; x `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī&]
|
|
[s7; &]
|
|
[s7; -|String y `= x.ToString();&]
|
|
[s7; -|DUMP(y);&]
|
|
[s7; &]
|
|
[s16; y `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī&]
|
|
[s7; &]
|
|
[s7; -|y.Cat(`" (appended)`");&]
|
|
[s7; -|x `= y.ToWString();&]
|
|
[s7; &]
|
|
[s16; x `= characters 280`-300: ĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪī
|
|
(appended)-|&]
|
|
[s5; &]
|
|
[s5; [/ (Note: y content is displayed as result of conversion from utf`-8
|
|
encoded data)]&]
|
|
[s5; &]
|
|
[s3; 4. Date and Time&]
|
|
[s5; To represent date and time, U`+`+ provides Date and Time concrete
|
|
types.&]
|
|
[s5; &]
|
|
[s7; -|Date date `= GetSysDate();&]
|
|
[s0; &]
|
|
[s16; date `= 01/21/2007&]
|
|
[s5; &]
|
|
[s5; All data members of Date structure are public:&]
|
|
[s5; &]
|
|
[s16; date.year `= 2007&]
|
|
[s16; date.month `= 1&]
|
|
[s16; date.day `= 21&]
|
|
[s5; &]
|
|
[s5; Dates can be compared:&]
|
|
[s5; &]
|
|
[s16; date > Date(1970, 1, 1) `= true&]
|
|
[s5; &]
|
|
[s5; Adding a number to Date adds a number of days to it:&]
|
|
[s5; &]
|
|
[s16; date `+ 1 `= 01/22/2007&]
|
|
[s5; &]
|
|
[s5; Subtraction of dates yields a number of days between them:&]
|
|
[s5; &]
|
|
[s16; date `- Date(1970, 1, 1) `= 13534&]
|
|
[s5; &]
|
|
[s5; U`+`+ defines the beginning and the end of era, most algorithms
|
|
can safely assume that as minimal and maximal values Date can
|
|
represent:&]
|
|
[s0; &]
|
|
[s16; Date`::Low() `= 01/01/`-4000&]
|
|
[s16; Date`::High() `= 01/01/4000&]
|
|
[s0; -|&]
|
|
[s5; &]
|
|
[s5; Time is [/ derived] from Date, adding members to represent time:&]
|
|
[s5; &]
|
|
[s7; -|Time time `= GetSysTime();&]
|
|
[s5; &]
|
|
[s16; time `= 01/21/2007 23:28:59&]
|
|
[s16; (Date`&)time `= 01/21/2007&]
|
|
[s16; (int)time.hour `= 23&]
|
|
[s16; (int)time.minute `= 28&]
|
|
[s16; (int)time.second `= 59&]
|
|
[s5; &]
|
|
[s5; Times can be compared:&]
|
|
[s5; &]
|
|
[s16; time > Time(1970, 0, 0) `= true&]
|
|
[s5; &]
|
|
[s5; Warning: As Time is derived from the Date, most operations automatically
|
|
convert Time back to Date. You have to use ToTime conversion
|
|
function to convert Date to Time:&]
|
|
[s5; &]
|
|
[s16; time > date `= false&]
|
|
[s16; time > ToTime(date) `= true&]
|
|
[s16; &]
|
|
[s5; &]
|
|
[s5; Like Date, Time supports add and subtract operations, but numbers
|
|
represent seconds (using int64 datatype):&]
|
|
[s5; &]
|
|
[s16; time `+ 1 `= 01/21/2007 23:29:00&]
|
|
[s16; time `+ 24 `* 3600 `= 01/22/2007 23:28:59&]
|
|
[s16; time `- date `= 0&]
|
|
[s16; time `- ToTime(date) `= 84539&]
|
|
[s5; &]
|
|
[s5; Time also defines era limits:&]
|
|
[s5; &]
|
|
[s16; Time`::Low() `= 01/01/`-4000 00:00:00&]
|
|
[s16; Time`::High() `= 01/01/4000 00:00:00&]
|
|
[s5;/ &]
|
|
[s3; 5. AsString, ToString and operator<<&]
|
|
[s5; U`+`+ Core provides simple yet effective standard schema for
|
|
converting values to default textual form.&]
|
|
[s5; System is based on the combination of template functions [/ (following
|
|
code is part of U`+`+ headers)]:&]
|
|
[s5; &]
|
|
[s7; template <class T>&]
|
|
[s7; inline String AsString(const T`& x)&]
|
|
[s7; `{&]
|
|
[s7; -|return x.ToString();&]
|
|
[s7; `}&]
|
|
[s7; &]
|
|
[s7; template <class T>&]
|
|
[s7; inline Stream`& operator<<(Stream`& s, const T`& x)&]
|
|
[s7; `{&]
|
|
[s7; -|s << AsString(x);&]
|
|
[s7; -|return s;&]
|
|
[s7; `}&]
|
|
[s7; &]
|
|
[s7; template <class T>&]
|
|
[s7; inline String`& operator<<(String`& s, const T`& x)&]
|
|
[s7; `{&]
|
|
[s7; -|s.Cat(AsString(x));&]
|
|
[s7; -|return s;&]
|
|
[s7; `}&]
|
|
[s5; &]
|
|
[s5; Client types have to either define String [*/ ToString] method
|
|
(usually more convenient) or specialize [*/ AsString] template.
|
|
Such types can be appended to Streams or Strings using [*/ operator<<].
|
|
Of course, U`+`+ value types and primitive types have required
|
|
items predefined by U`+`+:&]
|
|
[s5; &]
|
|
[s7; -|FileOut fout(ConfigFile(`"test.txt`"));&]
|
|
[s7; -|String sout;&]
|
|
[s7; -|&]
|
|
[s7; -|fout << 1.23 << `' `' << GetSysDate() << `' `' << GetSysTime();&]
|
|
[s7; -|sout << 1.23 << `' `' << GetSysDate() << `' `' << GetSysTime();&]
|
|
[s7; &]
|
|
[s16; sout `= 1.23 01/22/2007 01/22/2007 17:58:58&]
|
|
[s5; &]
|
|
[s5; Getting client types involved into this schema is not too difficult
|
|
(example shows both methods):&]
|
|
[s7; struct BinFoo `{&]
|
|
[s7; -|int x;&]
|
|
[s7; -|&]
|
|
[s7; -|String [* ToString]() const `{ return FormatIntBase(x, 2);
|
|
`}&]
|
|
[s7; -|&]
|
|
[s7; -|BinFoo(int x) : x(x) `{`}&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s7; struct RomanFoo `{&]
|
|
[s7; -|int x;&]
|
|
[s7; -|&]
|
|
[s7; -|RomanFoo(int x) : x(x) `{`}&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s7; namespace Upp `{&]
|
|
[s7; template <>&]
|
|
[s7; String Upp`::[* AsString](const RomanFoo`& a) `{ return FormatIntRoman(a.x);
|
|
`}&]
|
|
[s7; `};&]
|
|
[s7; .......&]
|
|
[s7; &]
|
|
[s7; -|sout << BinFoo(30) << `' `' << RomanFoo(30);&]
|
|
[s7; &]
|
|
[s7; &]
|
|
[s16; sout `= 11110 xxx&]
|
|
[s5; &]
|
|
[s3; 6. Value&]
|
|
[s5; U`+`+ provides one special value type, Value, that can be used
|
|
to store and retrieve other values.&]
|
|
[s5; &]
|
|
[s7; -|Value a `= 1;&]
|
|
[s7; -|Value b `= 2.34;&]
|
|
[s7; -|Value c `= GetSysDate();&]
|
|
[s7; -|Value d `= `"hello`";&]
|
|
[s5; &]
|
|
[s5; Usually, value types define typecast operator to Value and constructor
|
|
from Value, so that interaction is for the most part seamless:&]
|
|
[s5; &]
|
|
[s7; -|int x `= a;&]
|
|
[s7; -|double y `= b;&]
|
|
[s7; -|Date z `= c;&]
|
|
[s7; -|String s `= d;&]
|
|
[s7; &]
|
|
[s16; x `= 1&]
|
|
[s16; y `= 2.34&]
|
|
[s16; z `= 01/24/2007&]
|
|
[s16; s `= hello&]
|
|
[s5; &]
|
|
[s5; As for primitive types, Value seamlessly works with [* int], [* int64],
|
|
[* bool] and [* double].&]
|
|
[s5; Casting Value to a type that it does not contain causes runtime
|
|
error. On the other hand, conversion between related types is
|
|
possible:&]
|
|
[s5; &]
|
|
[s7; &]
|
|
[s7; -|double i `= a;&]
|
|
[s7; -|int j `= b;&]
|
|
[s7; -|Time k `= c;&]
|
|
[s7; -|WString t `= d;&]
|
|
[s7; &]
|
|
[s16; i `= 1&]
|
|
[s16; j `= 2&]
|
|
[s16; k `= 01/24/2007&]
|
|
[s16; t `= hello&]
|
|
[s5; &]
|
|
[s5; To determine type of value stored in Value, you can use [* Is]
|
|
method:&]
|
|
[s5; &]
|
|
[s16; a.Is<int>() `= true&]
|
|
[s16; a.Is<double>() `= false&]
|
|
[s16; b.Is<double>() `= true&]
|
|
[s16; c.Is<int>() `= false&]
|
|
[s16; c.Is<Date>() `= true&]
|
|
[s16; d.Is<String>() `= true&]
|
|
[s5; &]
|
|
[s5; Note that Is tests for absolute type match, not for compatible
|
|
types. For that reason, for widely used compatible types utility
|
|
functions are defined:&]
|
|
[s5; &]
|
|
[s16; &]
|
|
[s16; IsNumber(a) `= true&]
|
|
[s16; IsNumber(b) `= true&]
|
|
[s16; IsDateTime(c) `= true&]
|
|
[s16; IsString(d) `= true&]
|
|
[s5; &]
|
|
[s3; 7. Null&]
|
|
[s5; U`+`+ defines a special Null constant to represent an empty
|
|
value. This constant is convertible to many value types including
|
|
primitive types double, int and int64 (defined as lowest number
|
|
the type can represent). If type supports ordering (<, >), all
|
|
values of the type are greater than Null value. To test whether
|
|
a value is empty, use IsNull function.&]
|
|
[s5; &]
|
|
[s7; -|int x `= Null;&]
|
|
[s7; -|int y `= 120;&]
|
|
[s7; -|Date d `= Null;&]
|
|
[s7; -|Date e `= GetSysDate();&]
|
|
[s7; &]
|
|
[s16; IsNull(x) `= true&]
|
|
[s16; IsNull(y) `= false&]
|
|
[s16; IsNull(d) `= true&]
|
|
[s16; e > d `= true&]
|
|
[s0; &]
|
|
[s5; C`+`+ language note: Null is the only instance of Nuller type.
|
|
Assigning Null to primitive types is achieved by cast operators
|
|
of Nuller, other types can do it using constructor from Nuller.&]
|
|
[s5; As a special case, if Value contains Null, it is convertible
|
|
to any value type that can contain Null:&]
|
|
[s5; &]
|
|
[s7; &]
|
|
[s7; -|Value v `= x;&]
|
|
[s7; -|e `= v;&]
|
|
[s7; &]
|
|
[s16; IsNull(e) `= true&]
|
|
[s5; &]
|
|
[s5; Function Nvl is U`+`+ analog of well known SQL function coalesce
|
|
(ifnull, Nvl), which returns the first non`-null argument (or
|
|
Null if all are Null).&]
|
|
[s7; &]
|
|
[s7; -|int a `= Null;&]
|
|
[s7; -|int b `= 123;&]
|
|
[s7; -|int c `= 1;&]
|
|
[s7; &]
|
|
[s16; Nvl(a, b, c) `= 123&]
|
|
[s5; &]
|
|
[s3; 8. Client types and Value, RawValue, RichValue&]
|
|
[s5; There are two Value compatibility levels. The simple one, [*/ RawValue],
|
|
has little requirements for the type used `- only copy constructor
|
|
and assignment operator are required:&]
|
|
[s5; &]
|
|
[s7; struct RawFoo `{&]
|
|
[s7; -|String x;&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s5; &]
|
|
[s5; (int this case, default copy constructor and assignment operator
|
|
are provided by compiler).&]
|
|
[s5; &]
|
|
[s7; &]
|
|
[s7; -|RawFoo h;&]
|
|
[s7; -|h.x `= `"hello`";&]
|
|
[s7; -|Value q `= RawToValue(h);&]
|
|
[s7; &]
|
|
[s16; q.Is<Foo>() `= true&]
|
|
[s16; q.To<Foo>().x `= `"hello`"&]
|
|
[s7; &]
|
|
[s5; [* RichValue] level Values provide more operations for Value `-
|
|
equality test, IsNull test, hashing, conversion to text and serialization.
|
|
In order to make serialization work, type must also have assigned
|
|
an integer id (client types should use ids in range 10000..20000).
|
|
Type can provide the support for these operations via template
|
|
function specializations or (perhaps more convenient) using defined
|
|
methods and inheriting from ValueType base class template:&]
|
|
[s7; &]
|
|
[s7; struct Foo : ValueType<Foo, 10010> `{&]
|
|
[s7; -|int x;&]
|
|
[s7; -|&]
|
|
[s7; -|Foo(const Nuller`&) `{ x `= Null; `}&]
|
|
[s7; -|Foo(int x) : x(x) `{`}&]
|
|
[s7; -|Foo() `{`}&]
|
|
[s7; &]
|
|
[s7; -|String ToString() const `{ return AsString(x);
|
|
`}&]
|
|
[s7; -|unsigned GetHashValue() const `{ return x; `}&]
|
|
[s7; -|void Serialize(Stream`& s) `{ s % x; `}&]
|
|
[s7; -|bool operator`=`=(const Foo`& b) const `{ return x `=`= b.x;
|
|
`}&]
|
|
[s7; -|bool IsNullInstance() const `{ return IsNull(x); `}-|&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s7; INITBLOCK `{&]
|
|
[s7; -|Value`::Register<Foo>();&]
|
|
[s7; `}&]
|
|
[s7; .......&]
|
|
[s7; &]
|
|
[s7; -|Value a `= [* RichToValue](Foo(54321));&]
|
|
[s7; -|Value b `= RichToValue(Foo(54321));&]
|
|
[s7; &]
|
|
[s16; (a `=`= b) `= true&]
|
|
[s16; IsNull(a) `= false&]
|
|
[s16; v.Get<Foo>() `= 54321&]
|
|
[s7; &]
|
|
[s7; -|String s `= StoreAsString(a);&]
|
|
[s7; -|LoadFromString(v, s);&]
|
|
[s7; &]
|
|
[s16; v.Get<Foo>() `= 54321&]
|
|
[s5; &]
|
|
[s5; To avoid RichToValue and ValueTo calls, the client type can
|
|
also provide constructor from Value and cast operator to Value:&]
|
|
[s5; &]
|
|
[s7; struct Foo : ValueType<Foo, 10010> `{&]
|
|
[s7; -|int x;&]
|
|
[s7; -|&]
|
|
[s7; ......&]
|
|
[s7; -|&]
|
|
[s7; -|operator Value() `{ return RichToValue(`*this); `}&]
|
|
[s7; -|Foo(const Value`& v) `{ `*this `= v.Get<Foo>(); `}&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s7; ......&]
|
|
[s7; &]
|
|
[s7; -|Value c `= Foo(321);&]
|
|
[s7; -|Foo x `= c;&]
|
|
[s7; &]
|
|
[s16; x `= 123&]
|
|
[s5; &]
|
|
[s3; 9. CombineHash&]
|
|
[s5; To simplify providing of high quality hash codes for composite
|
|
types, U`+`+ provides CombineHash utility class. This class uses
|
|
GetHashValue function to gather hash codes of all values and
|
|
combines them to provide final hash value for composite type:&]
|
|
[s7; &]
|
|
[s7; struct Foo `{&]
|
|
[s7; -|String a;&]
|
|
[s7; -|int b;&]
|
|
[s7; -|&]
|
|
[s7; -|unsigned [* GetHashValue]() const `{ return [* CombineHash](a,
|
|
b); `}&]
|
|
[s7; `};&]
|
|
[s7; &]
|
|
[s5; Note that GetHashValue is defined as function template that
|
|
calls GetHashValue method of its argument, therefore defining
|
|
GetHashValue method defines GetHashValue function too.&]
|
|
[s7; &]
|
|
[s7; -|Foo x;&]
|
|
[s7; -|x.a `= `"world`";&]
|
|
[s7; -|x.b `= 22;&]
|
|
[s7; &]
|
|
[s16; GetHashValue(x) `= 4272824901&]
|
|
[s16; &]
|
|
[s7; -|x.a << `'!`';&]
|
|
[s7; &]
|
|
[s16; GetHashValue(x) `= 3378606405&]
|
|
[s5; &]
|
|
[s3; Recommended tutorials:&]
|
|
[s5; If you want to learn more, we have several tutorials that you
|
|
can find useful:&]
|
|
[s5;l160;i150;O0;~~~32; [^topic`:`/`/Core`/srcdoc`/Tutorial`$en`-us^ Containers
|
|
Tutorial] `- everything you should know about NTL (Not standard
|
|
Template Library) containers. This is the natural continuation
|
|
of issues raised in this article.&]
|
|
[s5;l160;i150;O0;~~~32; [^topic`:`/`/CtrlLib`/srcdoc`/Tutorial`$en`-us^ GUI
|
|
tutorial] `- learn about creating GUI application with U`+`+.]] |