Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

variant lite - A C++17-like variant, a type-safe union for C++98, C++11 and later in a single-file header-only library

License

NotificationsYou must be signed in to change notification settings

martinmoene/variant-lite

Repository files navigation

LanguageLicenseBuild StatusBuild statusVersionLatest downloadConanVcpkgTry it onlineTry it on godbolt online

Contents

Example usage

#include"nonstd/variant.hpp"#include<cassert>#include<string>usingnamespacenonstd;intmain(){    std::string hello ="hello, world";     variant<char,int,long, std::string > var;        var ='v' ;assert( get<0 >( var ) =='v' );assert( get<char>( var ) =='v' );    var =7  ;assert( get<int >( var ) ==7  );    var =42L ;assert( get<long>( var ) ==42L );        var = hello;assert( get<std::string>( var ) == hello );}

Compile and run

prompt>g++ -std=c++98 -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe

In a nutshell

variant lite is a single-file header-only library to represent a type-safe union. The library aims to provide aC++17-like variant for use with C++98 and later. If available, std::variant is used.

Features and properties of variant lite are ease of installation (single header), freedom of dependencies other than the standard library and control over object alignment (if needed).variant lite shares the approach to in-place tags withany-lite,expected-lite and withoptional-lite and these libraries can be used together.

Limitations of variant lite concern the number of alternative types and the number of visitor arguments. The maximum number of types and visitor arguments are configurable viascript generate_header.py (default: 16 types, 5 visitor arguments). With C++98, the alternative types are required to be of different type and there's no move construction, move assignment and emplacement.variant lite does not provide allocator-extended constructors.

License

variant lite is distributed under theBoost Software License.

Dependencies

variant lite has no other dependencies than theC++ standard library.

Installation

variant lite is a single-file header-only library. Putvariant.hpp in theinclude folder directly into the project source tree or somewhere reachable from your project.

Or, if you use theconan package manager, you might follow these steps:

  1. Create source file./main.cpp, e.g. with the contents of the example code above.

  2. Create./conanfile.txt file with a reference tovariant-lite in therequires section:

    [requires]variant-lite/1.2.2  # variant-lite/2.0.0 when available[generators]cmake
  3. Create./CMakeLists.txt:

    cmake_minimum_required(VERSION 3.1)project(variant-example CXX)include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)conan_basic_setup()add_executable(${PROJECT_NAME} main.cpp)target_link_libraries(${PROJECT_NAME}${CONAN_LIBS})
  4. Run the following commands:

    mkdir build && cd buildconan install .. --settings arch=x86 --settings compiler=gcccmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Releasecmake --build . --config Release

Synopsis

Contents

Types in namespace nonstd

PurposeTypeNotes
Type-safe uniontemplate< class T0...T6 >
classvariant
non-standard: may hold up to seven types
Default constructibleclassmonostateType to make variant default constructible
Error reportingclassbad_variant_access 
In-place constructionstructin_place_tag 
 in_placeselect type or index for in-place construction
 in_place_typeselect type for in-place construction
 in_place_indexselect index for in-place construction
 nonstd_lite_in_place_type_t( T)macro for alias template in_place_type_t<T>
 nonstd_lite_in_place_index_t( T )macro for alias template in_place_index_t<T>
Variant sizetemplate<...>
structvariant_size< variant<...> >
 
 variant_size_v< T >C++14
 variant_size_V( T )macro for nonstd::variant_size<T>::value
Select variant typetemplate< std::size_t I, ...>
structvariant_alternative< I, variant<...> >
 
 variant_alternative_t< I, T >C++11
 variant_alternative_T( I, T )macro for typename nonstd::variant_alternative<I,T >::type

Interface ofvariant lite

KindStdMethodResult
Construction variant()default-construct first type
  variant( Tx const & x )copy-construct with value type Tx
 C++11variant( Tx && x )move-construct with value type Tx
  variant( variant const & rhs )copy-construct from other variant
 C++11variant( variant && rhs )move-construct from other variant
 C++11template< class T, class... Args >
explicitvariant( in_place_type_t(T), Args&&... args)
in-place-construct type T
 C++11template< class T, class U, class... Args >
explicitvariant( in_place_type_t(T),
 std::initializer_list<U> il, Args&&... args )
in-place-construct type T
 C++11template< std::size_t I, class... Args >
explicitvariant( in_place_index_t(I), Args&&... args )
in-place-construct type at index I
 C++11template< size_t I, class U, class... Args>
explicitvariant( in_place_index_t(I),
 std::initializer_list<U> il, Args&&... args )
in-place-construct type at index I
Destruction ~variant()destruct current content
Assignment variant &operator=( variant const & rhs )copy-assign from other
 C++11variant &operator=( variant && rhs )move-assign from other
 C++11template< class Tx >
variant &operator=( Tx && t )
move-assign from value
 < C++11template< class Tx >
variant &operator=( Tx const & t )
copy-assign from value;
non-standard
State std::size_tindex() constindex of current content's type
  boolvalueless_by_exception() consttrue if no content is present
EmplaceC++11template< class T, class... Args >
T &emplace( Args&&... args )
emplace type T
 C++11template< class T, class U, class... Args >
T &emplace( std::initializer_list<U> il, Args&&... args )
emplace type T
 C++11template< size_t I, class... Args >
variant_alternative_t<I,variant> &
emplace( Args&&... args );
emplace type at index I
 C++11template< size_t I, class U, class... Args >
variant_alternative_t<I,variant> &
emplace( std::initializer_list<U> il, Args&&... args )
emplace type at index I
Swap voidswap( variant & other );swap with other

Algorithms forvariant lite

KindStdFunction
Relational operators  
== template<...>
booloperator==( variant<...> const & v, variant<...> const & w )
!= template<...>
booloperator==( variant<...> const & v, variant<...> const & w )
< template<...>
booloperator<( variant<...> const & v, variant<...> const & w )
> template<...>
booloperator>( variant<...> const & v, variant<...> const & w )
<= template<...>
booloperator<=( variant<...> const & v, variant<...> const & w )
>= template<...>
booloperator>=( variant<...> const & v, variant<...> const & w )
Content  
contains value of type T template< class T, ...>
boolholds_alternative( variant<...> const & v ) [noexcept]
get by type template< class R, ...>
R &
get( variant<...> & v, in_place_type_t(R) = in_place )
get by type (rvalue)C++11template< class R, ...>
R &&
get( variant<...> && v, in_place_type_t(R) = in_place )
get by type (const) template< class R, ...>
R const &
get( variant<...> const & v, in_place_type_t(R) = in_place )
get by type (const rvalue)C++11template< class R, ...>
R const &&
get( variant<...> const && v, in_place_type_t(R) = in_place )
get by index template< std::size_t I, ...>
typename variant_alternative< I, variant<...> >::type &
get( variant<...> & v, in_place_index_t(I) = in_place )
get by index (rvalue)C++11template< std::size_t I, ...>
typename variant_alternative< I, variant<...> >::type &&
get( variant<...> && v, in_place_index_t(I) = in_place )
get by index (const) template< std::size_t I, ...>
typename variant_alternative< I, variant<...> >::type const &
get( variant<...> const & v, in_place_index_t(I) = in_place )
get by index (const rvalue)C++11template< std::size_t I, ...>
typename variant_alternative< I, variant<...> >::type const &&
get( variant<...> const && v, in_place_index_t(I) = in_place )
get_if by type template< class T, ...>
typename detail::add_pointer<T>::type
get_if( variant<...> * pv, in_place_type_t(T) = in_place )
get_if by type (const) template< class T, ...>
typename detail::add_pointer<const T>::type
get_if( variant<...> const * pv, in_place_type_t(T) = in_place)
get_if by index template< std::size_t I, ...>
typename detail::add_pointer< typename variant_alternative<I, variant<T0, T1, T2, T3, T4, T5, T6> >::type >::type
get_if( variant<...> * pv, in_place_index_t(I) = in_place )
get_if by index (const) template< std::size_t I, ...>
typename detail::add_pointer< const typename variant_alternative<I, variant<T0, T1, T2, T3, T4, T5, T6> >::type >::type
get_if( variant<...> const * pv, in_place_index_t(I) = in_place )
swap template<...>
voidswap( variant<...> & x, variant<...> & y )
visitNote 1template< class Visitor, class Variant >
Variantvisit( Visitor const & vis, Variant const & v )
Hash support  
variantC++11template<...> structhash< variant<...> >;
monostateC++11template<> structhash< monostate >;

Note 1: visitor is limited to always return a Variant.

Information macros

variant_CONFIG_MAX_TYPE_COUNT
The maximum number of types thevariant can hold as configured via scriptgenerate_header.py.

variant_CONFIG_MAX_VISITOR_ARG_COUNT
The maximum number of visitor arguments as configured via scriptgenerate_header.py.

Configuration macros

Tweak header

If the compiler supports__has_include(),variant lite supports thetweak header mechanism. Provide yourtweak header asnonstd/variant.tweak.hpp in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like#define boolean_CPLUSPLUS 201103L.

Standard selection macro

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

Selectstd::variant ornonstd::variant

At default,variant lite usesstd::variant if it is available and lets you use it via namespacenonstd. You can however override this default and explicitly request to usestd::variant or variant lite'snonstd::variant asnonstd::variant via the following macros.

-Dvariant_CONFIG_SELECT_VARIANT=variant_VARIANT_DEFAULT
Define this tovariant_VARIANT_STD to selectstd::variant asnonstd::variant. Define this tovariant_VARIANT_NONSTD to selectnonstd::variant asnonstd::variant. Default is undefined, which has the same effect as defining tovariant_VARIANT_DEFAULT.

Disable exceptions

-Dvariant_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). Default is undefined.

Disable [[nodiscard]]

-Dvariant_CONFIG_NO_NODISCARD=0Define this to 1 if you want to compile without [[nodiscard]]. Note that the default of markingclass bad_variant_access with [[nodiscard]] is not part of the C++17 standard. The rationale to use [[nodiscard]] is that unnoticed discarded access error values may break the error handling flow.

Presence ofvariant_size_V() simulation macro

-Dvariant_CONFIG_OMIT_VARIANT_SIZE_V_MACRO=0
Define this macro to 1 to omit thevariant_size_V(T) macro. Default is 0.

Presence ofvariant_alternative_T() simulation macro

-Dvariant_CONFIG_OMIT_VARIANT_ALTERNATIVE_T_MACRO=0
Define this macro to 1 to omit thevariant_alternative_T(I,T) macro. Default is 0.

Macros to control alignment

Ifvariant lite 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,variant lite tries to determine proper alignment itself. If this doesn't work out, you can control alignment via the following macros. See also sectionImplementation notes.

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

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

-Dvariant_CONFIG_ALIGN_AS_FALLBACK=pod_type
Define this to the pod-type to use for alignment if the algorithm ofvariant lite cannot find a suitable POD type to use for alignment. Default isdouble.

Reported to work with

The table below mentions the compiler versionsvariant lite is reported to work with.

OSCompilerVersions
WindowsClang/LLVM?
 GCC5.2.0
 Visual C++
(Visual Studio)
8 (2005), 9 (2008), 10 (2010), 11 (2012),
12 (2013), 14 (2015), 15 (2017), 16 (2019)
GNU/LinuxClang/LLVM3.5.0
 GCC4.8.4
OS X??

Building the tests

To build the tests you need:

Thelest test framework is included in thetest folder.

The following steps assume that thevariant lite source code has been cloned into a directory namedc:\variant-lite.

  1. Create a directory for the build outputs for a particular architecture.Here we use c:\variant-lite\build-win-x86-vc10.

     cd c:\variant-lite md build-win-x86-vc10 cd build-win-x86-vc10
  2. Configure CMake to use the compiler of your choice (runcmake --help for a list).

     cmake -G "Visual Studio 10 2010" ..
  3. Build the test suite in the Debug configuration (alternatively use Release).

     cmake --build . --config Debug
  4. Run the test suite.

     ctest -V -C Debug

All tests should pass, indicating your platform is supported and you are ready to usevariant lite.

Implementation notes

Object allocation and alignment

variant lite 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 [10, part 2].

Ifvariant lite 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,variant lite tries to determine proper alignment using meta programming. If this doesn't work out, you can control alignment via three macros.

variant lite 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 -Dvariant_CONFIG_MAX_ALIGN_HACK=1 the underlying type is aligned as the most restricted type instruct max_align_t. This potentially wastes many bytes per variant if the actually required alignment is much less, e.g. 24 bytes used instead of the 2 bytes required.

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

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

  5. At default,variant lite 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 usingalignment_of<>.
    • Find a POD type from the listalignment_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 invariant_CONFIG_ALIGN_AS_FALLBACK (default double).

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

The class templatealignment_of<> is gleaned fromBoost.TypeTraits, alignment_of [14].

For more information on constructed unions and alignment, see [10-14].

Other implementations of variant

Notes and References

Acknowledgments

Thanks to @flexferrum for making the number of variant types and visitor argumentsconfigurable.Thanks to @siffiejoe for contributing to fixinglifetime,noexcept andhash issues.

References

[1] CppReference.Variant.

[2] ISO/IEC WG21.N4606, section 20.7 Variants. July 2016.

[3] Axel Naumann.Variant: a type-safe union for C++17 (v8). June 2016.

[4] Peter Dimov.Valueless Variants Considered Harmful. March 2016.

[5] Anthony Williams.Standardizing Variant: Difficult Decisions. June 2015

[6] Andrzej Krzemieński.Constexpr unions. December 2012.

[7] Agustín Bergé.Eggs.Variant - Part I. August 2014.

[8] Agustín Bergé.Eggs.Variant - Part II (the constexpr experience). March 2015.

[9] Andrei Alexandrescu.An Implementation of Discriminated Unions in C++. August 2002.

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

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

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

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

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

Presentations

[15] Ben Deane.Using Types Effectively. CppCon 2016.

Appendix

A.1 Compile-time information

The version ofvariant lite is available via tag[.version]. The following tags are available for information on the compiler and on the C++ standard library used:[.compiler],[.stdc++],[.stdlanguage] and[.stdlibrary].

A.2 Variant lite test specification

click to expand

variant: Disallows non-default constructible as first typevariant: Allows non-default constructible as second and later type (first: int)variant: Allows non-default constructible as second and later type (first: monostate)variant: Allows multiple identical types (C++11)variant: Allows to default-construct variantvariant: Allows to copy-construct from variantvariant: Allows to move-construct from variant (C++11)variant: Allows to move-construct if-noexcept from variant (C++11)variant: Allows to obtain the index of the current typevariant: Allows to inspect if variant is "valueless by exception"variant: Allows to copy-assign from variantvariant: Allows to copy-assign mutually empty variantvariant: Allows to copy-assign from empty variantvariant: Allows to copy-assign to empty variantvariant: Allows to move-assign from variant (C++11)variant: Allows to move-assign mutually empty variant (C++11)variant: Allows to move-assign from empty variant (C++11)variant: Allows to move-assign to empty variant (C++11)variant: Allows to construct from element valuevariant: Allows to copy-construct from elementvariant: Allows to move-construct from element (C++11)variant: Allows to convert-copy-construct from elementvariant: Allows to convert-move-construct from element (C++11)variant: Allows to copy-assign from element valuevariant: Allows to move-assign from element valuevariant: Allows to copy-assign from elementvariant: Allows to move-assign from element (C++11)variant: Allows to convert-copy-assign from element valuevariant: Allows to copy-construct from elements in intializer-list based on type (C++11)variant: Allows to move-construct from elements in intializer-list based on type (C++11)variant: Allows to in-place copy-construct element based on type (C++11)variant: Allows to in-place move-construct element based on type (C++11)variant: Allows to in-place copy-construct element based on index (C++11)variant: Allows to in-place move-construct element based on index (C++11)variant: Allows to in-place copy-construct elements from intializer-list based on type (C++11)variant: Allows to in-place move-construct elements from intializer-list based on type (C++11)variant: Allows to in-place copy-construct elements from intializer-list based on index (C++11)variant: Allows to in-place move-construct elements from intializer-list based on index (C++11)variant: Allows to copy-emplace element based on type (C++11)variant: Disallows to copy-emplace non-unique element type on type (C++11)variant: Allows to move-emplace element based on type (C++11)variant: Allows to copy-emplace element based on index (C++11)variant: Allows to move-emplace element based on index (C++11)variant: Allows to copy-emplace elements from intializer-list based on type (C++11)variant: Allows to move-emplace elements from intializer-list based on type (C++11)variant: Allows to copy-emplace elements from intializer-list based on index (C++11)variant: Allows to move-emplace elements from intializer-list based on index (C++11)variant: Allows to swap variants, same index (member)variant: Allows to swap variants, different index (member)variant: Allows to visit contents (args: 1; configured max args: 5)variant: Allows to visit contents (args: 2; configured max args: 5)variant: Allows to visit contents (args: 3; configured max args: 5)variant: Allows to visit contents, rvalue reference (args: 1; configured max args: 5)variant: Allows to check for content by typevariant: Allows to get element by typevariant: Allows to get element by indexvariant: Allows to get pointer to element or NULL by typevariant: Allows to get pointer to element or NULL by indexvariant: Allows to compare variantsvariant: Allows to swap variants, same index (non-member)variant: Allows to swap variants, different index (non-member)monostate: Allows to make variant default-constructiblebad_variant_access: Indicates invalid variant accessvariant_size<>: Allows to obtain number of element types (configured max types: 16)variant_size_v<>: Allows to obtain number of element types (C++14; configured max types: 16)variant_size_V(): Allows to obtain number of element types (non-standard: macro; configured max types: 16)variant_alternative<>: Allows to select type by indexvariant_alternative_t<>: Allows to select type by index (C++11)variant_alternative_T(): Allows to select type by index (non-standard: macro)std::hash<>: Allows to obtain hash (C++11)tweak header: reads tweak header if supported [tweak]

About

variant lite - A C++17-like variant, a type-safe union for C++98, C++11 and later in a single-file header-only library

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp