QEverCloud  6.1.0
Unofficial Evernote Cloud API for Qt
Public Member Functions | Friends | List of all members
qevercloud::Optional< T > Class Template Reference

#include <Optional.h>

Public Member Functions

 Optional ()
 
 Optional (const Optional &o)
 
template<typename X >
 Optional (const Optional< X > &o)
 
 Optional (const T &value)
 
template<typename X >
 Optional (const X &value)
 
Optionaloperator= (const Optional &o)
 
template<typename X >
Optionaloperator= (const Optional< X > &o)
 
Optionaloperator= (const T &value)
 
template<typename X >
Optionaloperator= (const X &value)
 
 operator const T & () const
 
 operator T& ()
 
const T & ref () const
 
T & ref ()
 
bool isSet () const
 Checks if value is set. More...
 
void clear ()
 
Optionalinit ()
 
T * operator-> ()
 
const T * operator-> () const
 
value (T defaultValue=T()) const
 
bool isEqual (const Optional< T > &other) const
 
bool operator== (const Optional< T > &other) const
 
bool operator!= (const Optional< T > &other) const
 
bool operator== (const T &other) const
 
bool operator!= (const T &other) const
 
 Optional (Optional &&other)
 
Optionaloperator= (Optional &&other)
 
 Optional (T &&other)
 
Optionaloperator= (T &&other)
 

Friends

template<typename X >
class Optional
 
void swap (Optional &first, Optional &second)
 

Detailed Description

template<typename T>
class qevercloud::Optional< T >

Supports optional values.

Most of the fields in the Evernote API structs are optional. But C++ does not support this notion directly.

To implement the concept of optional values conventional Thrift C++ wrapper uses a special field of a struct type where each field is of type bool with the same name as a field in the struct. This bool flag indicated was the field with the same name in the outer struct assigned or not.

While this method have its advantages (obviousness and simplicity) I found it very inconvenient to work with. You have to check by hand that both values (value itself and its __isset flag) are in sync. There is no checks whatsoever against an error and such an error is too easy to make.

So for my library I created a special class that supports the optional value notion explicitly. Basically Optional class just holds a bool value that tracks the fact that a value was assigned. But this tracking is done automatically and attempts to use unassigned values throw exceptions. In this way errors are much harder to make and it's harder for them to slip through testing unnoticed too.

Constructor & Destructor Documentation

◆ Optional() [1/7]

template<typename T >
qevercloud::Optional< T >::Optional ( )
inline

Default constructor. Default Optional is not set.

◆ Optional() [2/7]

template<typename T >
qevercloud::Optional< T >::Optional ( const Optional< T > &  o)
inline

Copy constructor.

◆ Optional() [3/7]

template<typename T >
template<typename X >
qevercloud::Optional< T >::Optional ( const Optional< X > &  o)
inline

Template copy constructor. Allows to be initialized with Optional of any compatible type.

◆ Optional() [4/7]

template<typename T >
qevercloud::Optional< T >::Optional ( const T &  value)
inline

Initialization with a value of the type T. Note: it's implicit.

◆ Optional() [5/7]

template<typename T >
template<typename X >
qevercloud::Optional< T >::Optional ( const X &  value)
inline

Template initialization with a value of any compatible type.

◆ Optional() [6/7]

template<typename T >
qevercloud::Optional< T >::Optional ( Optional< T > &&  other)
inline

◆ Optional() [7/7]

template<typename T >
qevercloud::Optional< T >::Optional ( T &&  other)
inline

Member Function Documentation

◆ clear()

template<typename T >
void qevercloud::Optional< T >::clear ( )
inline

Clears an Optional.

Optional<int> o(1);
o.clear();
cout << o; // exception

◆ init()

template<typename T >
Optional& qevercloud::Optional< T >::init ( )
inline

Fast way to initialize an Optional with a default value.

It's very useful for structs.

struct S2 {int f;};
struct S {int f1; Optional<S2> f2};
Optional<S> o; // o.isSet() != ture
// without init() it's cumbersome to access struct fields
// it's especially true for nested Optionals
o = S(); // now o is set
o->f2 = S2(); // and o.f2 is set
o->f2->f = 1; // so at last it can be used
// with init() it's simpler
o.init()->f2.init()->f = 1;
Returns
reference to itself

◆ isEqual()

template<typename T >
bool qevercloud::Optional< T >::isEqual ( const Optional< T > &  other) const
inline

Two optionals are equal if they are both not set or have equal values.

◆ isSet()

template<typename T >
bool qevercloud::Optional< T >::isSet ( ) const
inline

Checks if value is set.

Returns
true if Optional have been assigned a value and false otherwise.

Access to an unassigned ("not set") Optional lead to an exception.

◆ operator const T &()

template<typename T >
qevercloud::Optional< T >::operator const T & ( ) const
inline

Implicit conversion of Optional<T> to T.

const version.

◆ operator T&()

template<typename T >
qevercloud::Optional< T >::operator T& ( )
inline

Implicit conversion of Optional<T> to T.

Note: a reference is returned, not a copy.

◆ operator!=() [1/2]

template<typename T >
bool qevercloud::Optional< T >::operator!= ( const Optional< T > &  other) const
inline

◆ operator!=() [2/2]

template<typename T >
bool qevercloud::Optional< T >::operator!= ( const T &  other) const
inline

◆ operator->() [1/2]

template<typename T >
T* qevercloud::Optional< T >::operator-> ( )
inline

Two syntatic constructs come to mind to use for implementation of access to a struct's/class's field directly from Optional.

One is the dereference operator. This is what boost::optional uses. While it's conceptually nice I found it to be not a very convenient way to refer to structs, especially nested ones. So I overloaded the operator-> and use smart pointer semantics.

struct S1 {int f1;};
struct S2 {Optional<S1> f2;};
Optional<S2> o;
*((*o).f2).f1; // boost way, not implemented
o->f2->f1; // QEverCloud way

I admit, boost::optional is much more elegant overall. It uses pointer semantics quite clearly and in an instantly understandable way. It's universal (works for any type and not just structs). There is no need for implicit type concersions and so there is no subtleties because of it. And so on.

But then referring to struct fields is a chore. And this is the most common use case of Optionals in QEverCloud.

So I decided to use non-obvious-on-the-first-sight semantics for my Optional. IMO it's much more convenient when gotten used to.

◆ operator->() [2/2]

template<typename T >
const T* qevercloud::Optional< T >::operator-> ( ) const
inline

const version.

◆ operator=() [1/6]

template<typename T >
Optional& qevercloud::Optional< T >::operator= ( const Optional< T > &  o)
inline

Assignment.

◆ operator=() [2/6]

template<typename T >
template<typename X >
Optional& qevercloud::Optional< T >::operator= ( const Optional< X > &  o)
inline

Template assignment with an Optional of any compatible value.

◆ operator=() [3/6]

template<typename T >
Optional& qevercloud::Optional< T >::operator= ( const T &  value)
inline

Assignment with a value of the type T.

◆ operator=() [4/6]

template<typename T >
template<typename X >
Optional& qevercloud::Optional< T >::operator= ( const X &  value)
inline

Template assignment with a value of any compatible type.

◆ operator=() [5/6]

template<typename T >
Optional& qevercloud::Optional< T >::operator= ( Optional< T > &&  other)
inline

◆ operator=() [6/6]

template<typename T >
Optional& qevercloud::Optional< T >::operator= ( T &&  other)
inline

◆ operator==() [1/2]

template<typename T >
bool qevercloud::Optional< T >::operator== ( const Optional< T > &  other) const
inline

◆ operator==() [2/2]

template<typename T >
bool qevercloud::Optional< T >::operator== ( const T &  other) const
inline

◆ ref() [1/2]

template<typename T >
T& qevercloud::Optional< T >::ref ( )
inline

Returs reference to the holded value.

There are contexts in C++ where impicit type conversions can't help. For example:

Optional<QStringList> l;
for(auto s : l); // you will hear from your compiler

Explicit type conversion can be used...

Optional<QStringList> l;
for(auto s : static_cast<QStringList&>(l)); // ugh...

... but this is indeed ugly as hell.

So I implemented ref() function that returns a reference to the holded value.

Optional<QStringList> l;
for(auto s : l.ref()); // not ideal but OK

◆ ref() [2/2]

template<typename T >
const T& qevercloud::Optional< T >::ref ( ) const
inline

Returs a reference to the holded value.

const version.

◆ value()

template<typename T >
T qevercloud::Optional< T >::value ( defaultValue = T()) const
inline

The function is sometimes useful to simplify checking for the value being set.

Parameters
defaultValueThe value to return if Optional is not set.
Returns
Optional value if set and defaultValue otherwise.

Friends And Related Function Documentation

◆ Optional

template<typename T >
template<typename X >
friend class Optional
friend

◆ swap

template<typename T >
void swap ( Optional< T > &  first,
Optional< T > &  second 
)
friend