Skip to content

Latest commit

 

History

History
251 lines (176 loc) · 16.3 KB

README_cpp98.md

File metadata and controls

251 lines (176 loc) · 16.3 KB

status_value cpp98: A class for status and optional value for C++98 and later

Language Language License Build Status Build status Version download Conan Try it on wandbox Try it on godbolt online

status_value is a single-file header-only library for objects that represent a status and an optional value. This variant is intended for use with C++98 and later. The library is based on the proposal for status_value [1].

Contents

Example usage

#include "nonstd/status_value_cpp98.hpp"

#include <cstdlib>
#include <iostream>
#include <string>

using namespace nonstd;

status_value< std::string, int >
to_int( char const * const text ) 
{
    char * pos = NULL;
    long value = strtol( text, &pos, 0 );

    if ( pos != text ) return status_value< std::string, int >( "Excellent", value );
    else               return status_value< std::string, int >( std::string("'") + text + "' isn't a number" );
}

int main( int argc, char * argv[] )
{
    char const * const text = argc > 1 ? argv[1] : "42";

    status_value<std::string, int> svi = to_int( text );

    if ( svi ) std::cout << svi.status() << ": '" << text << "' is " << *svi << ", ";
    else       std::cout << "Error: " << svi.status();

    return 0; // VC6
}

Compile and run

prompt> g++ -std=c++98 -Wall -I../include -o 01-basic_cpp98.exe 01-basic_cpp98.cpp && 01-basic_cpp98.exe 123 && 01-basic_cpp98.exe abc
Excellent: '123' is 123, Error: 'abc' isn't a number

In a nutshell

status_value is a single-file header-only library to represent objects that contain a status and an optional value. The library is an implementation of the proposal for std::status_value [1,2] for use with C++98 and later.

Features and properties of status_value are ease of installation (single header), construction of a status, or a status and a value from a value that is convertible to the underlying type, move-construction (C++11) / copy-construction (C++98) from another status_value of the same type, testing for the presence of a value, operators and method value() for checked access to the value and access to the status.

Not provided are copy-construction of a status_value under C++11 (by design), ... .

For more examples, see [1].

License

status_value is distributed under the Boost Software License.

Dependencies

status_value has no other dependencies than the C++ standard library.

Installation

status_value is a single-file header-only library. Put status_value.hpp directly into the project source tree or somewhere reachable from your project.

Synopsis

Contents

Interface of status_value

Kind Method Result
Type
 
template<typename S>
class bad_status_value_access;
 
C++11 bad_status_value_access( S s ) move-construct from status
C++98 bad_status_value_access( S const & s ) copy-construct from status
     
Type
 
template<typename S, typename V>
class status_value;
 
Construction status_value() = delete   or   private disallow default construction
C++11 status_value( status_value && other ) move-construct from other
C++98 status_value( status_value const & other ) copy-construct from other
  status_value( status_type const & s ) copy-construct from status
C++11 status_value( status_type const & s, value_type && v ) copy-construct from status,
move construct from value
  status_value( status_type const & s, value_type const & v ) copy-construct from status and value
Destruction ~status_value() status, value destroyed if present
Observers operator bool() const true if contains value
  bool has_value() const true if contains value
  status_type const & status() const the status
  value_type const & value() const the value (const ref);
see note 1
  value_type & value() the value (non-const ref);
see note 1
  value_type const & operator *() const the value (const ref);
see note 1
  value_type & operator *() the value (non-const ref);
see note 1
  value_type const & operator ->() const the element value (const ref);
see note 1
  value_type & operator ->() the element value (non-const ref);
see note 1

Note 1: checked access: if no content, throws bad_status_value_access containing status value.

Configuration macros

Tweak header

If the compiler supports __has_include(), status_value lite supports the tweak header mechanism. Provide your tweak header as nonstd/status_value.tweak.hpp in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like #define nsstsv_CPLUSPLUS 201103L.

Standard selection macro

-Dnsstsv_CPLUSPLUS=199711L
Define this macro to override the auto-detection of the supported C++ standard, if your compiler does not set the __cpluplus macro correctly.

Disable exceptions

-Dnssv_CONFIG_NO_EXCEPTIONS=0
Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via -fno-exceptions). Disabling exceptions will force contract violation to call std::abort(). Default is 0.

Enable compilation errors

-Dnssv_CONFIG_CONFIRMS_COMPILATION_ERRORS=0
Define this macro to 1 to experience the by-design compile-time errors of the library in the test suite. Default is 0.

Macros to control alignment

If status_value is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiled as pre-C++11, status_value tries to determine proper alignment itself. If this doesn't work out, you can control alignment via the following macros. See also section Implementation notes.

-Dnsstsv_CONFIG_MAX_ALIGN_HACK=0
Define this to 1 to use the max align hack for alignment. Default is 0.

-Dnsstsv_CONFIG_ALIGN_AS=pod-type
Define this to the pod-type you want to align to (no default).

-Dnsstsv_CONFIG_ALIGN_AS_FALLBACK=pod-type
Define this to the pod-type to use for alignment if the algorithm of status_value cannot find a suitable POD type to use for alignment. Default is double.

Reported to work with

status_value_cpp98 is reported to work with the following compilers:

  • Visual C++ 6 SP6 (VS6), VC10, (VS2010), VC11 (VS2012), VC12 (VS2013), VC14 (VS2015)
  • GNUC 5.2.0 with -std=c++98, -std=c++03, -std=c++11, -std=c++14, -std=c++1y
  • clang 3.6, 3.7 with -std=c++03, -std=c++11 (on Travis)

Implementation notes

Object allocation and alignment

status_value reserves POD-type storage for an object of the underlying type inside a union to prevent unwanted construction and uses placement new to construct the object when required. Using non-placement new (malloc) to obtain storage, ensures that the memory is properly aligned for the object's type, whereas that's not the case with placement new.

If you access data that's not properly aligned, it 1) may take longer than when it is properly aligned (on x86 processors), or 2) it may terminate the program immediately (many other processors).

Although the C++ standard does not guarantee that all user-defined types have the alignment of some POD type, in practice it's likely they do [6, part 2].

If status_value is compiled as C++11 or later, C++11 alignment facilities are used for storage of the underlying object. When compiling as pre-C++11, status_value tries to determine proper alignment using meta programming. If this doesn't work out, you can control alignment via three macros.

status_value uses the following rules for alignment:

  1. If the program compiles as C++11 or later, C++11 alignment facilities are used.

  2. If you define -Dnsstsv_CONFIG_MAX_ALIGN_HACK=1 the underlying type is aligned as the most restricted type in struct max_align_t. This potentially wastes many bytes per optional if the actually required alignment is much less, e.g. 24 bytes used instead of the 2 bytes required.

  3. If you define -Dnsstsv_CONFIG_ALIGN_AS=pod-type the underlying type is aligned as pod-type. It's your obligation to specify a type with proper alignment.

  4. If you define -Dnsstsv_CONFIG_ALIGN_AS_FALLBACK=pod-type the fallback type for alignment of rule 5 below becomes pod-type. It's your obligation to specify a type with proper alignment.

  5. At default, status_value tries to find a POD type with the same alignment as the underlying type.

    The algorithm for alignment of 5. is:

    • Determine the alignment A of the underlying type using alignment_of<>.
    • Find a POD type from the list alignment_types with exactly alignment A.
    • If no such POD type is found, use a type with a relatively strict alignment requirement such as double; this type is specified in nsstsv_CONFIG_ALIGN_AS_FALLBACK (default double).

Note that the algorithm of 5. differs from the one Andrei Alexandrescu uses in [6, part 2].

The class template alignment_of<> is gleaned from Boost.TypeTraits, alignment_of [10]. The storage type storage_t<> is adapted from the one I created for optional lite [10].

For more information on constructed unions and alignment, see [5-9].

Notes and references

[1] Lawrence Crowl and Chris Mysen. p0262 - A Class for Status and Optional Value (latest), 14 February 2016. N4233, 10 October 2014.

[2] Lawrence Crowl. p0157 - Handling Disappointment in C++ (latest), 7 July 2015.

[3] Vicente J. Botet Escriba. p0323 - A proposal to add a utility class to represent expected object (latest) (PDF). (r6, r5, r4, r3, r2, r1, r0, draft).

[4] Fernando Cacciola and Andrzej Krzemieński. N3793 - A proposal to add a utility class to represent optional objects (Revision 5). 03 October 2013. N3672 r4, N3527 r3, N3406 r2, N1878 r1, N3966 - Fixes for optional objects.

[5] Andrei Alexandrescu. Generic: Discriminated Unions part 1, part 2, part 3. April 2002.

[6] Herb Sutter. Style Case Study #3: Construction Unions. GotW #85. 2009

[7] Kevin T. Manley. Using Constructed Types in C++ Unions. C/C++ Users Journal, 20(8), August 2002.

[8] StackOverflow. Determining maximum possible alignment in C++.

[9] Boost.TypeTraits, alignment_of ( code ).

[10] Martin Moene. optional lite (optional.hpp).

Appendix

A.1 status_value test specification

click to expand

status_value<>: Disallows default construction
status_value<>: Allows construction from only status
status_value<>: Allows construction from status and non-default-constructible value
status_value<>: Allows construction from copied status and moved value (C++11)
status_value<>: Allows construction from copied status and copied value
status_value<>: Disallows copy-construction from other status_value of the same type (C++11)
status_value<>: Allows move-construction from other status_value of the same type (C++11)
status_value<>: Allows to observe its status
status_value<>: Allows to observe the presence of a value (has_value())
status_value<>: Allows to observe the presence of a value (operator bool)
status_value<>: Allows to observe its value
status_value<>: Allows to observe its value (operator*)
status_value<>: Allows to observe its value (operator->)
status_value<>: Throws when observing non-engaged (value())
status_value<>: Throws when observing non-engaged (operator*())
status_value<>: Throws when observing non-engaged (operator->())
tweak header: reads tweak header if supported [tweak]