From a10fc11b5c61674dfbd9eaefeec72aa9288695f1 Mon Sep 17 00:00:00 2001 From: Fytch Date: Wed, 18 Dec 2019 21:53:14 +0100 Subject: [PATCH 01/25] add more compilers to travis Squashed commit of the following: commit 91dda92af04621cf526ddd83e7d11297147925ae Author: Fytch Date: Wed Dec 18 21:42:51 2019 +0100 maybe this? no more stdlib flags commit 2038f09cc7099a5b4f35fc96df38951ab8be565e Author: Fytch Date: Wed Dec 18 21:32:43 2019 +0100 maybe this dist works? commit a34655a9490b6a797305a5f9f979480d4e9ba9ec Author: Fytch Date: Wed Dec 18 21:24:27 2019 +0100 remove libc++ from clang 7,8,9 in travis commit 02bf4442a9a99613a1cbbc194e3e0a24b17f4bc9 Author: Fytch Date: Wed Dec 18 21:19:15 2019 +0100 nicer build matrix commit 5fc8044e933eac740ebdd271594540112d0e63f1 Author: Fytch Date: Wed Dec 18 21:11:01 2019 +0100 add more compilers to travis --- .travis.yml | 110 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index 65a01f5..d635118 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: cpp -dist: trusty -sudo: required +sudo: false +dist: xenial notifications: email: false @@ -15,7 +15,9 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-4.9 - env: COMPILER=g++-4.9 + env: + - CC=gcc-4.9 + - CXX=g++-4.9 - compiler: gcc addons: apt: @@ -23,7 +25,9 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-5 - env: COMPILER=g++-5 + env: + - CC=gcc-5 + - CXX=g++-5 - compiler: gcc addons: apt: @@ -31,7 +35,9 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-6 - env: COMPILER=g++-6 + env: + - CC=gcc-6 + - CXX=g++-6 - compiler: gcc addons: apt: @@ -39,7 +45,9 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-7 - env: COMPILER=g++-7 + env: + - CC=gcc-7 + - CXX=g++-7 - compiler: gcc addons: apt: @@ -47,7 +55,19 @@ matrix: - ubuntu-toolchain-r-test packages: - g++-8 - env: COMPILER=g++-8 + env: + - CC=gcc-8 + - CXX=g++-8 + - compiler: gcc + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-9 + env: + - CC=gcc-9 + - CXX=g++-9 - compiler: clang addons: apt: @@ -59,7 +79,8 @@ matrix: - libc++-dev - libc++abi-dev env: - - COMPILER=clang++-3.6 + - CC=clang-3.6 + - CXX=clang++-3.6 - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" - compiler: clang addons: @@ -72,7 +93,8 @@ matrix: - libc++-dev - libc++abi-dev env: - - COMPILER=clang++-3.7 + - CC=clang-3.7 + - CXX=clang++-3.7 - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" - compiler: clang addons: @@ -85,7 +107,8 @@ matrix: - libc++-dev - libc++abi-dev env: - - COMPILER=clang++-3.8 + - CC=clang-3.8 + - CXX=clang++-3.8 - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" - compiler: clang addons: @@ -98,7 +121,8 @@ matrix: - libc++-dev - libc++abi-dev env: - - COMPILER=clang++-3.9 + - CC=clang-3.9 + - CXX=clang++-3.9 - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" - compiler: clang addons: @@ -111,49 +135,85 @@ matrix: - libc++-dev - libc++abi-dev env: - - COMPILER=clang++-4.0 + - CC=clang-4.0 + - CXX=clang++-4.0 - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" - compiler: clang addons: apt: sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: - clang-5.0 - - libc++-dev - - libc++abi-dev env: - - COMPILER=clang++-5.0 - - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" + - CC=clang-5.0 + - CXX=clang++-5.0 - compiler: clang addons: apt: sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' packages: - clang-6.0 - - libc++-dev - - libc++abi-dev env: - - COMPILER=clang++-6.0 - - CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-lc++" + - CC=clang-6.0 + - CXX=clang++-6.0 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: + - clang-7 + env: + - CC=clang-7 + - CXX=clang++-7 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: + - clang-8 + env: + - CC=clang-8 + - CXX=clang++-8 + - compiler: clang + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main' + key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' + packages: + - clang-9 + env: + - CC=clang-9 + - CXX=clang++-9 script: - uname -a - cmake --version - - $COMPILER --version + - $CC --version + - $CXX --version - mkdir bin_noexcept - cd bin_noexcept - - cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_CXX_COMPILER=$COMPILER -DPROGRAMOPTIONS_BUILD_TEST=OFF -DPROGRAMOPTIONS_NO_EXCEPTIONS=ON + - cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX -DPROGRAMOPTIONS_BUILD_TEST=OFF -DPROGRAMOPTIONS_NO_EXCEPTIONS=ON - cmake --build . - cd .. - mkdir bin - cd bin - - cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_CXX_COMPILER=$COMPILER + - cmake .. $CMAKE_FLAGS -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX - cmake --build . - ./Test From be2fc7552eac83e766a00a4963b841d5daf3723d Mon Sep 17 00:00:00 2001 From: Fytch Date: Wed, 18 Dec 2019 21:58:57 +0100 Subject: [PATCH 02/25] use oldstyle initialization of references because of issues with older compilers --- ProgramOptions.hxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProgramOptions.hxx b/ProgramOptions.hxx index d068567..ac445ca 100644 --- a/ProgramOptions.hxx +++ b/ProgramOptions.hxx @@ -109,7 +109,7 @@ namespace po { #endif // PROGRAMOPTIONS_WINDOWS color_resetter( std::ostream& stream, color_t color ) - : m_stream{ stream } { + : m_stream(stream) { // don't use an initializer list here because of gcc-4.8.5 #ifdef PROGRAMOPTIONS_WINDOWS m_stream << std::flush; m_console = GetStdHandle( STD_OUTPUT_HANDLE ); From c9246c808f529f7e0be331d58cdaca20ad1d0737 Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 20:20:30 +0100 Subject: [PATCH 03/25] CMake: include Catch2 using add_subdirectory instead --- CMakeLists.txt | 6 ++++-- test/bind.cxx | 2 +- test/callback.cxx | 2 +- test/defaults.cxx | 2 +- test/errors.cxx | 2 +- test/exceptions.cxx | 2 +- test/integer.cxx | 2 +- test/option_packs.cxx | 2 +- test/str2flt.cxx | 2 +- test/str2int.cxx | 2 +- test/str2uint.cxx | 2 +- test/string.cxx | 2 +- test/test.cxx | 2 +- test/wellformed.cxx | 2 +- 14 files changed, 17 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa3c0dd..8ee74d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,7 @@ elseif( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) set( PROGRAMOPTIONS_MS_OPTIONS TRUE ) endif() -include_directories( "./" ) -include_directories( "./ext/Catch2/single_include/catch2/" ) +include_directories( "${CMAKE_CURRENT_LIST_DIR}/" ) if( PROGRAMOPTIONS_GNU_OPTIONS ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti" ) @@ -40,8 +39,11 @@ if( PROGRAMOPTIONS_NO_COLORS ) endif() if( PROGRAMOPTIONS_BUILD_TEST ) + add_subdirectory( "${CMAKE_CURRENT_LIST_DIR}/ext/Catch2" ) + file( GLOB_RECURSE test_src test/*.cxx ) add_executable( Test ${test_src} ) + target_link_libraries( Test Catch2::Catch2 ) endif() if( PROGRAMOPTIONS_BUILD_EXAMPLES ) diff --git a/test/bind.cxx b/test/bind.cxx index aa8787c..879ff24 100644 --- a/test/bind.cxx +++ b/test/bind.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/callback.cxx b/test/callback.cxx index ca118ff..4963012 100644 --- a/test/callback.cxx +++ b/test/callback.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/defaults.cxx b/test/defaults.cxx index 47bd495..8a6f98e 100644 --- a/test/defaults.cxx +++ b/test/defaults.cxx @@ -1,4 +1,4 @@ -#include +#include #include TEST_CASE( "defaults", "[ProgramOptions]" ) { diff --git a/test/errors.cxx b/test/errors.cxx index 89c7531..8d68068 100644 --- a/test/errors.cxx +++ b/test/errors.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/exceptions.cxx b/test/exceptions.cxx index 0157f2e..09753bc 100644 --- a/test/exceptions.cxx +++ b/test/exceptions.cxx @@ -1,4 +1,4 @@ -#include +#include #undef NDEBUG #undef PROGRAMOPTIONS_NO_EXCEPTIONS #include diff --git a/test/integer.cxx b/test/integer.cxx index cf55893..b95a3e9 100644 --- a/test/integer.cxx +++ b/test/integer.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/option_packs.cxx b/test/option_packs.cxx index d83b497..fd1739c 100644 --- a/test/option_packs.cxx +++ b/test/option_packs.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/str2flt.cxx b/test/str2flt.cxx index e5cf4a6..81a09a2 100644 --- a/test/str2flt.cxx +++ b/test/str2flt.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/test/str2int.cxx b/test/str2int.cxx index 9c7f3ff..af6c4de 100644 --- a/test/str2int.cxx +++ b/test/str2int.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/test/str2uint.cxx b/test/str2uint.cxx index fde6109..8684c28 100644 --- a/test/str2uint.cxx +++ b/test/str2uint.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/test/string.cxx b/test/string.cxx index 2bc040b..71f8d77 100644 --- a/test/string.cxx +++ b/test/string.cxx @@ -1,4 +1,4 @@ -#include +#include #include #include "arg_provider.hxx" diff --git a/test/test.cxx b/test/test.cxx index b3143fb..4ed06df 100644 --- a/test/test.cxx +++ b/test/test.cxx @@ -1,2 +1,2 @@ #define CATCH_CONFIG_MAIN -#include +#include diff --git a/test/wellformed.cxx b/test/wellformed.cxx index b7a4a9e..6abb40f 100644 --- a/test/wellformed.cxx +++ b/test/wellformed.cxx @@ -1,4 +1,4 @@ -#include +#include #include TEST_CASE( "wellformed", "[ProgramOptions]" ) { From 1657f93ae91dbad106200ba6aa0a3cea20bcf5d2 Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 20:20:49 +0100 Subject: [PATCH 04/25] README: change readme to remove bad advice --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2498656..d31fc78 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ It is highly recommended that you at least briefly skim through the chapters [** The quickest way to get started is to download *ProgramOptions.hxx* as well as one of the samples and go from there. ### `sample.cxx` -The default choice. Using *ProgramOptions.hxx* incorrectly or failing to meet a function's preconditions will throw an exception which will, by default, terminate the program and display a useful message, explaining where exactly things went wrong. If you don't want the program to be terminated, you may provide your own `try` and `catch` blocks to deal with [`std::logic_error`s](http://en.cppreference.com/w/cpp/error/logic_error). +The default choice. Using *ProgramOptions.hxx* incorrectly or failing to meet a function's preconditions will throw an exception which will, by default, terminate the program and display a useful message, explaining where exactly things went wrong. ### `sample_noexcept.cxx` Using this sample is only recommended if you are already somewhat familiar with *ProgramOptions.hxx*. Incorrect programs will crash without any messages unless your STL implementation does so when [`assert`ions](http://en.cppreference.com/w/cpp/error/assert) fail. From e82a49b5dbe39d25d0fc7f201e9aaafec070d617 Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 20:21:30 +0100 Subject: [PATCH 05/25] move ProgramOptions.hxx to include/ --- CMakeLists.txt | 2 +- ProgramOptions.hxx => include/ProgramOptions.hxx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ProgramOptions.hxx => include/ProgramOptions.hxx (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ee74d9..eb51903 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ elseif( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) set( PROGRAMOPTIONS_MS_OPTIONS TRUE ) endif() -include_directories( "${CMAKE_CURRENT_LIST_DIR}/" ) +include_directories( "${CMAKE_CURRENT_LIST_DIR}/include/" ) if( PROGRAMOPTIONS_GNU_OPTIONS ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti" ) diff --git a/ProgramOptions.hxx b/include/ProgramOptions.hxx similarity index 100% rename from ProgramOptions.hxx rename to include/ProgramOptions.hxx From 13f95d0f989b9e5c9198d6b46d1ba221cbffb49f Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 20:51:44 +0100 Subject: [PATCH 06/25] CMake: add target "ProgramOptionsHxx" so that users can link against the library when they've added it via add_subdirectory --- CMakeLists.txt | 97 ++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb51903..ebb2fbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,56 +1,69 @@ -cmake_minimum_required( VERSION 3.1 ) -project( ProgramOptions ) +cmake_minimum_required( VERSION 3.5 ) + +if( NOT DEFINED PROJECT_NAME ) + set( PROGRAMOPTIONS_NOT_SUBPROJECT ON ) +endif() + +project( ProgramOptions LANGUAGES CXX VERSION 1.0.0 ) set( CMAKE_CXX_STANDARD 11 ) set( CMAKE_CXX_STANDARD_REQUIRED ON ) set( CMAKE_CXX_EXTENSIONS OFF ) -option( PROGRAMOPTIONS_NO_EXCEPTIONS "disable exceptions" OFF ) -option( PROGRAMOPTIONS_NO_COLORS "disable colored output" OFF ) -option( PROGRAMOPTIONS_BUILD_TEST "build test" ON ) -option( PROGRAMOPTIONS_BUILD_EXAMPLES "build examples" ON ) - -if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR - CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR - CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) - set( PROGRAMOPTIONS_GNU_OPTIONS TRUE ) -elseif( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) - set( PROGRAMOPTIONS_MS_OPTIONS TRUE ) -endif() +add_library( ProgramOptionsHxx INTERFACE ) +target_include_directories( ProgramOptionsHxx INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include" ) -include_directories( "${CMAKE_CURRENT_LIST_DIR}/include/" ) +if( PROGRAMOPTIONS_NOT_SUBPROJECT ) + option( PROGRAMOPTIONS_NO_EXCEPTIONS "disable exceptions" OFF ) + option( PROGRAMOPTIONS_NO_COLORS "disable colored output" OFF ) + option( PROGRAMOPTIONS_BUILD_TEST "build test" ON ) + option( PROGRAMOPTIONS_BUILD_EXAMPLES "build examples" ON ) -if( PROGRAMOPTIONS_GNU_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb -fno-omit-frame-pointer" ) - set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG -s -flto" ) -endif() + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR + CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR + CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) + set( PROGRAMOPTIONS_GNU_OPTIONS TRUE ) + elseif( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) + set( PROGRAMOPTIONS_MS_OPTIONS TRUE ) + endif() -if( PROGRAMOPTIONS_NO_EXCEPTIONS ) - add_definitions( -DPROGRAMOPTIONS_NO_EXCEPTIONS ) if( PROGRAMOPTIONS_GNU_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions" ) - elseif( PROGRAMOPTIONS_MS_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb -fno-omit-frame-pointer" ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG -s -flto" ) endif() -endif() -if( PROGRAMOPTIONS_NO_COLORS ) - add_definitions( -DPROGRAMOPTIONS_NO_COLORS ) -endif() + if( PROGRAMOPTIONS_NO_EXCEPTIONS ) + add_definitions( -DPROGRAMOPTIONS_NO_EXCEPTIONS ) + if( PROGRAMOPTIONS_GNU_OPTIONS ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions" ) + elseif( PROGRAMOPTIONS_MS_OPTIONS ) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" ) + endif() + endif() -if( PROGRAMOPTIONS_BUILD_TEST ) - add_subdirectory( "${CMAKE_CURRENT_LIST_DIR}/ext/Catch2" ) + if( PROGRAMOPTIONS_NO_COLORS ) + add_definitions( -DPROGRAMOPTIONS_NO_COLORS ) + endif() - file( GLOB_RECURSE test_src test/*.cxx ) - add_executable( Test ${test_src} ) - target_link_libraries( Test Catch2::Catch2 ) -endif() + if( PROGRAMOPTIONS_BUILD_TEST ) + add_subdirectory( "${CMAKE_CURRENT_LIST_DIR}/ext/Catch2" ) -if( PROGRAMOPTIONS_BUILD_EXAMPLES ) - file( GLOB_RECURSE examples_src examples/*.cxx ) - foreach( src_name ${examples_src} ) - # CMake's regex engine doesn't support lazy evaluation (?), hence the hack below - string( REGEX REPLACE "^.*[^a-zA-Z_]([a-zA-Z_]+)\\.cxx$" "\\1" exe_name ${src_name} ) - add_executable( ${exe_name} ${src_name} ) - endforeach( src_name ${examples_src} ) + file( GLOB_RECURSE test_src test/*.cxx ) + add_executable( Test ${test_src} ) + target_link_libraries( Test + Catch2::Catch2 + ProgramOptionsHxx + ) + endif() + + if( PROGRAMOPTIONS_BUILD_EXAMPLES ) + file( GLOB_RECURSE examples_src examples/*.cxx ) + foreach( src_name ${examples_src} ) + # CMake's regex engine doesn't support lazy evaluation (?), hence the hack below + string( REGEX REPLACE "^.*[^a-zA-Z_]([a-zA-Z_]+)\\.cxx$" "\\1" exe_name ${src_name} ) + add_executable( ${exe_name} ${src_name} ) + + target_link_libraries( ${exe_name} ProgramOptionsHxx ) + endforeach( src_name ${examples_src} ) + endif() endif() From 71cc491f576bc163bdbb67e5a53ce74a6bffecd8 Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 21:57:36 +0100 Subject: [PATCH 07/25] README: expound integration with git and CMake --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d31fc78..7c99229 100644 --- a/README.md +++ b/README.md @@ -64,12 +64,27 @@ Using this sample is only recommended if you are already somewhat familiar with 1 Note that `-version` (with only a single hyphen) would be interpreted as the option `-v` with the argument `ersion`. ## Integration -*ProgramOptions.hxx* is very easy to integrate. After downloading the header file, all that it takes is a simple: +*ProgramOptions.hxx* is very easy to integrate. After downloading the header file from the ```include``` folder and putting it into your project folder, all it takes is a simple: ```cpp #include "ProgramOptions.hxx" ``` Don't forget to compile with C++11 enabled, i.e. with `-std=c++11`. +### git +If you want to integrate *ProgramOptions.hxx* into your project that uses [git](https://git-scm.com/), you can write: +``` +git submodule add https://github.com/Fytch/ProgramOptions.hxx third_party/ProgramOptions.hxx +``` +You may replace ```third_party/ProgramOptions.hxx``` by any path. + +### CMake +If you want to integrate *ProgramOptions.hxx* into your project that uses [CMake](https://cmake.org/), add the following to your ```CMakeLists.txt```: +```cmake +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/third_party/ProgramOptions.hxx") +target_link_libraries(YourExecutable ProgramOptionsHxx) +``` +You must replace ```/third_party/ProgramOptions.hxx``` by the correct path and ```YourExecutable``` by the targets that use *ProgramOptions.hxx*. + ## Usage Using *ProgramOptions.hxx* is straightforward; we'll explain it by means of practical examples. All examples shown here and more can be found in the [/examples](examples) directory, all of which are well-documented. From 56ae89ddec709af16e3f6456d7f81b90a8597244 Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 21:59:38 +0100 Subject: [PATCH 08/25] update copyright notice --- LICENSE.txt | 2 +- include/ProgramOptions.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 4375ed4..f00afe6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017-2018 Josua Rieder +Copyright (c) 2017-2020 Josua Rieder Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/include/ProgramOptions.hxx b/include/ProgramOptions.hxx index ac445ca..9535259 100644 --- a/include/ProgramOptions.hxx +++ b/include/ProgramOptions.hxx @@ -1,6 +1,6 @@ /* * ProgramOptions.hxx - a single-header program options parsing library for C++11 - * Copyright (C) 2017-2018 Josua Rieder (josua.rieder1996@gmail.com) + * Copyright (C) 2017-2020 Josua Rieder (josua.rieder1996@gmail.com) * Distributed under the MIT License. * For further information, see the enclosed file LICENSE.txt or * visit https://opensource.org/licenses/mit-license.html From 5e78cab066da3789b6892ca5e4e8ec751723ae1c Mon Sep 17 00:00:00 2001 From: Fytch Date: Sun, 19 Jan 2020 22:24:46 +0100 Subject: [PATCH 09/25] change code style: ( x ) -> (x), ditto for other brackets except {} --- CMakeLists.txt | 86 +- README.md | 192 ++-- examples/1 optimization.cxx | 14 +- examples/2 include.cxx | 28 +- examples/3 files.cxx | 50 +- examples/4 sum.cxx | 24 +- examples/5 bind.cxx | 48 +- examples/colors.cxx | 32 +- examples/detect_type.cxx | 14 +- examples/flag.cxx | 8 +- examples/getopt.cxx | 20 +- include/ProgramOptions.hxx | 1834 +++++++++++++++++------------------ sample.cxx | 28 +- sample_noexcept.cxx | 26 +- test/arg_provider.hxx | 20 +- test/bind.cxx | 142 +-- test/callback.cxx | 134 +-- test/defaults.cxx | 26 +- test/errors.cxx | 66 +- test/exceptions.cxx | 160 +-- test/integer.cxx | 120 +-- test/option_packs.cxx | 110 +-- test/str2flt.cxx | 102 +- test/str2int.cxx | 82 +- test/str2uint.cxx | 116 +-- test/string.cxx | 132 +-- test/wellformed.cxx | 28 +- 27 files changed, 1821 insertions(+), 1821 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ebb2fbd..3080d05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,69 +1,69 @@ -cmake_minimum_required( VERSION 3.5 ) +cmake_minimum_required(VERSION 3.5) -if( NOT DEFINED PROJECT_NAME ) - set( PROGRAMOPTIONS_NOT_SUBPROJECT ON ) +if(NOT DEFINED PROJECT_NAME) + set(PROGRAMOPTIONS_NOT_SUBPROJECT ON) endif() -project( ProgramOptions LANGUAGES CXX VERSION 1.0.0 ) -set( CMAKE_CXX_STANDARD 11 ) -set( CMAKE_CXX_STANDARD_REQUIRED ON ) -set( CMAKE_CXX_EXTENSIONS OFF ) +project(ProgramOptions LANGUAGES CXX VERSION 1.0.0) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) -add_library( ProgramOptionsHxx INTERFACE ) -target_include_directories( ProgramOptionsHxx INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include" ) +add_library(ProgramOptionsHxx INTERFACE) +target_include_directories(ProgramOptionsHxx INTERFACE "${CMAKE_CURRENT_LIST_DIR}/include") -if( PROGRAMOPTIONS_NOT_SUBPROJECT ) - option( PROGRAMOPTIONS_NO_EXCEPTIONS "disable exceptions" OFF ) - option( PROGRAMOPTIONS_NO_COLORS "disable colored output" OFF ) - option( PROGRAMOPTIONS_BUILD_TEST "build test" ON ) - option( PROGRAMOPTIONS_BUILD_EXAMPLES "build examples" ON ) +if(PROGRAMOPTIONS_NOT_SUBPROJECT) + option(PROGRAMOPTIONS_NO_EXCEPTIONS "disable exceptions" OFF) + option(PROGRAMOPTIONS_NO_COLORS "disable colored output" OFF) + option(PROGRAMOPTIONS_BUILD_TEST "build test" ON) + option(PROGRAMOPTIONS_BUILD_EXAMPLES "build examples" ON) - if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR - CMAKE_CXX_COMPILER_ID MATCHES "Intel" ) - set( PROGRAMOPTIONS_GNU_OPTIONS TRUE ) - elseif( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) - set( PROGRAMOPTIONS_MS_OPTIONS TRUE ) + CMAKE_CXX_COMPILER_ID MATCHES "Intel") + set(PROGRAMOPTIONS_GNU_OPTIONS TRUE) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set(PROGRAMOPTIONS_MS_OPTIONS TRUE) endif() - if( PROGRAMOPTIONS_GNU_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb -fno-omit-frame-pointer" ) - set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG -s -flto" ) + if(PROGRAMOPTIONS_GNU_OPTIONS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-deprecated -fno-rtti") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -ggdb -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -DNDEBUG -s -flto") endif() - if( PROGRAMOPTIONS_NO_EXCEPTIONS ) - add_definitions( -DPROGRAMOPTIONS_NO_EXCEPTIONS ) - if( PROGRAMOPTIONS_GNU_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions" ) - elseif( PROGRAMOPTIONS_MS_OPTIONS ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" ) + if(PROGRAMOPTIONS_NO_EXCEPTIONS) + add_definitions(-DPROGRAMOPTIONS_NO_EXCEPTIONS) + if(PROGRAMOPTIONS_GNU_OPTIONS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + elseif(PROGRAMOPTIONS_MS_OPTIONS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") endif() endif() - if( PROGRAMOPTIONS_NO_COLORS ) - add_definitions( -DPROGRAMOPTIONS_NO_COLORS ) + if(PROGRAMOPTIONS_NO_COLORS) + add_definitions(-DPROGRAMOPTIONS_NO_COLORS) endif() - if( PROGRAMOPTIONS_BUILD_TEST ) - add_subdirectory( "${CMAKE_CURRENT_LIST_DIR}/ext/Catch2" ) + if(PROGRAMOPTIONS_BUILD_TEST) + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/ext/Catch2") - file( GLOB_RECURSE test_src test/*.cxx ) - add_executable( Test ${test_src} ) - target_link_libraries( Test + file(GLOB_RECURSE test_src test/*.cxx) + add_executable(Test ${test_src}) + target_link_libraries(Test Catch2::Catch2 ProgramOptionsHxx ) endif() - if( PROGRAMOPTIONS_BUILD_EXAMPLES ) - file( GLOB_RECURSE examples_src examples/*.cxx ) - foreach( src_name ${examples_src} ) + if(PROGRAMOPTIONS_BUILD_EXAMPLES) + file(GLOB_RECURSE examples_src examples/*.cxx) + foreach(src_name ${examples_src}) # CMake's regex engine doesn't support lazy evaluation (?), hence the hack below - string( REGEX REPLACE "^.*[^a-zA-Z_]([a-zA-Z_]+)\\.cxx$" "\\1" exe_name ${src_name} ) - add_executable( ${exe_name} ${src_name} ) + string(REGEX REPLACE "^.*[^a-zA-Z_]([a-zA-Z_]+)\\.cxx$" "\\1" exe_name ${src_name}) + add_executable(${exe_name} ${src_name}) - target_link_libraries( ${exe_name} ProgramOptionsHxx ) - endforeach( src_name ${examples_src} ) + target_link_libraries(${exe_name} ProgramOptionsHxx) + endforeach(src_name ${examples_src}) endif() endif() diff --git a/README.md b/README.md index 7c99229..bc93fd8 100644 --- a/README.md +++ b/README.md @@ -94,16 +94,16 @@ The following snippet is the complete source code of a simple program expecting #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] // corresponds to --optimization - .abbreviation( 'O' ) // corresponds to -O - .type( po::u32 ); // expects an unsigned 32-bit integer + parser["optimization"] // corresponds to --optimization + .abbreviation('O') // corresponds to -O + .type(po::u32); // expects an unsigned 32-bit integer - parser( argc, argv ); // parses the command line arguments + parser(argc, argv); // parses the command line arguments - auto&& O = parser[ "optimization" ]; - if( !O.available() ) + auto&& O = parser["optimization"]; + if(!O.available()) std::cout << "no optimization level set!\n"; else std::cout << "optimization level set to " << O.get().u32 << '\n'; @@ -132,30 +132,30 @@ By calling the method `.multi()` we're telling the library to store *all* values #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] - .abbreviation( 'O' ) - .type( po::u32 ) - .fallback( 0 ); // if --optimization is not explicitly specified, assume 0 + parser["optimization"] + .abbreviation('O') + .type(po::u32) + .fallback(0); // if --optimization is not explicitly specified, assume 0 - parser[ "include-path" ] // corresponds to --include-path - .abbreviation( 'I' ) // corresponds to -I - .type( po::string ) // expects a string - .multi(); // allows multiple arguments for the same option + parser["include-path"] // corresponds to --include-path + .abbreviation('I') // corresponds to -I + .type(po::string) // expects a string + .multi(); // allows multiple arguments for the same option - parser( argc, argv ); + parser(argc, argv); - auto&& O = parser[ "optimization" ]; + auto&& O = parser["optimization"]; // .was_set() reports whether the option was specified by the user or relied on the predefined fallback value. - std::cout << "optimization level (" << ( O.was_set() ? "manual" : "auto" ) << ") = " << O.get().u32 << '\n'; + std::cout << "optimization level (" << (O.was_set() ? "manual" : "auto") << ") = " << O.get().u32 << '\n'; - auto&& I = parser[ "include-path" ]; + auto&& I = parser["include-path"]; // .size() and .count() return the number of arguments given. Without .multi(), their return value would always be <= 1. std::cout << "include paths (" << I.size() << "):\n"; // Here, the non-template .begin() / .end() methods are being used. Their value type is po::value, // which is not a value in itself but contains the desired values as members, i.e. i.string. - for( auto&& i : I ) + for(auto&& i : I) std::cout << '\t' << i.string << '\n'; } ``` @@ -180,49 +180,49 @@ Note that, in order to pass arguments starting with a hyphen to the unnamed para #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] - .abbreviation( 'O' ) - .description( "set the optimization level (default: -O0)" ) - .type( po::u32 ) - .fallback( 0 ); - - parser[ "include-path" ] - .abbreviation( 'I' ) - .description( "add an include path" ) - .type( po::string ) + parser["optimization"] + .abbreviation('O') + .description("set the optimization level (default: -O0)") + .type(po::u32) + .fallback(0); + + parser["include-path"] + .abbreviation('I') + .description("add an include path") + .type(po::string) .multi(); - parser[ "help" ] // corresponds to --help - .abbreviation( '?' ) // corresponds to -? - .description( "print this help screen" ) - .callback( [ & ]{ std::cout << parser << '\n'; } ); - // callbacks get invoked when the option occurs + parser["help"] // corresponds to --help + .abbreviation('?') // corresponds to -? + .description("print this help screen") + .callback([&]{ std::cout << parser << '\n'; }); + // callbacks get invoked when the option occurs - parser[ "" ] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c - // .type( po::string ) // redundant; default for the unnamed parameter - // .multi() // redundant; default for the unnamed parameter - .callback( [ & ]( std::string const& x ){ std::cout << "processed \'" << x << "\' successfully!\n"; } ); - // as .get_type() == po::string, the callback may take an std::string + parser[""] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c + // .type(po::string) // redundant; default for the unnamed parameter + // .multi() // redundant; default for the unnamed parameter + .callback([&](std::string const& x){ std::cout << "processed \'" << x << "\' successfully!\n"; }); + // as .get_type() == po::string, the callback may take an std::string // parsing returns false if at least one error has occurred - if( !parser( argc, argv ) ) { + if(!parser(argc, argv)) { std::cerr << "errors occurred; aborting\n"; return -1; } // we don't want to print anything else if the help screen has been displayed - if( parser[ "help" ].size() ) + if(parser["help"].size()) return 0; - std::cout << "processed files: " << parser[ "" ].size() << '\n'; + std::cout << "processed files: " << parser[""].size() << '\n'; - auto&& O = parser[ "optimization" ]; - std::cout << "optimization level (" << ( O.was_set() ? "manual" : "auto" ) << ") = " << O.get().u32 << '\n'; + auto&& O = parser["optimization"]; + std::cout << "optimization level (" << (O.was_set() ? "manual" : "auto") << ") = " << O.get().u32 << '\n'; - auto&& I = parser[ "include-path" ]; + auto&& I = parser["include-path"]; std::cout << "include paths (" << I.size() << "):\n"; - for( auto&& i : I ) + for(auto&& i : I) std::cout << '\t' << i.string << '\n'; } ``` @@ -269,63 +269,63 @@ In this example, we will employ already known mechanics but lay the focus on the #### Reading `.multi()` options: - `.begin()` and `.end()`: Random-access iterators that point to `po::value`s; thus you have to choose the right member when dereferencing, e.g. `.begin()->i32` -- `.begin< po::i32 >()` and `.end< po::i32 >()`: Random-access iterators that point to values of the specified type -- `.get( i )` (and `.size()`): Reference to `po::value`; there's also a `.get_or( i, v )` method, returning the second parameter if the index is out of range -- `.to_vector< po::i32 >()`: Returns a `std::vector` with elements of the specified type +- `.begin()` and `.end()`: Random-access iterators that point to values of the specified type +- `.get(i)` (and `.size()`): Reference to `po::value`; there's also a `.get_or(i, v)` method, returning the second parameter if the index is out of range +- `.to_vector()`: Returns a `std::vector` with elements of the specified type ```cpp #include #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - auto&& x = parser[ "" ] - .type( po::f64 ) // expects 64-bit floating point numbers - .multi() // allows multiple arguments - .fallback( -8, "+.5e2" ) // if no arguments were provided, assume these as default - .callback( [ & ]{ std::cout << "successfully parsed "; } ) - .callback( [ & ]( std::string const& x ){ std::cout << x; } ) - .callback( [ & ]{ std::cout << " which equals "; } ) - .callback( [ & ]( po::f64_t x ){ std::cout << x << '\n'; } ); + auto&& x = parser[""] + .type(po::f64) // expects 64-bit floating point numbers + .multi() // allows multiple arguments + .fallback(-8, "+.5e2") // if no arguments were provided, assume these as default + .callback([&]{ std::cout << "successfully parsed "; }) + .callback([&](std::string const& x){ std::cout << x; }) + .callback([&]{ std::cout << " which equals "; }) + .callback([&](po::f64_t x){ std::cout << x << '\n'; }); - parser( argc, argv ); + parser(argc, argv); - std::cout << "( + "; - for( auto&& i : x.to_vector< po::f64 >() ) // unnecessary copy; for demonstration purposes only + std::cout << "(+ "; + for(auto&& i : x.to_vector()) // unnecessary copy; for demonstration purposes only std::cout << i << ' '; - std::cout << ") = " << std::accumulate( x.begin< po::f64 >(), x.end< po::f64 >(), po::f64_t{} ) << '\n'; + std::cout << ") = " << std::accumulate(x.begin(), x.end(), po::f64_t{}) << '\n'; } ``` In action: ``` $ ./sum -( + -8 50 ) = 42 +(+ -8 50) = 42 $ ./sum 39.5 2.5 successfully parsed 39.5 which equals 39.5 successfully parsed 2.5 which equals 2.5 -( + 39.5 2.5 ) = 42 +(+ 39.5 2.5) = 42 $ ./sum 1e3 -1e0 -1e1 -2e2 successfully parsed 1e3 which equals 1000 successfully parsed -1e0 which equals -1 successfully parsed -1e1 which equals -10 successfully parsed -2e2 which equals -200 -( + 1000 -1 -10 -200 ) = 789 +(+ 1000 -1 -10 -200) = 789 $ ./sum inf -1 successfully parsed inf which equals inf successfully parsed -1 which equals -1 -( + inf -1 ) = inf +(+ inf -1) = inf $ ./sum 12 NaN successfully parsed 12 which equals 12 successfully parsed NaN which equals nan -( + 12 nan ) = nan +(+ 12 nan) = nan ``` ### Example 5 (`bind`) Until now, we defined the type, plurality and fallback value of each option manually by invoking `.type`, `.single`/`.multi` and `.fallback`. If we just want to extract the values from the parser and store them in a variable, `.bind` offers a more convenient and safer way of achieving this and ought to be preferred. `.bind` internally sets the type and the plurality (`.single`/`.multi`) of the corresponding option (but not the fallback). -We may bind options to variables of type `std::string`, to 32- or 64-bit signed integers, unsigned integer, floating point numbers or to STL containers consisting of elements of such type. If we want to use custom container types and/or custom insertion routines, we have to use `.bind_container( container&, inserter )` which accepts a binary function with the signature `inserter( container_t&, container_t::value_type const& )` (up to implicit conversion). +We may bind options to variables of type `std::string`, to 32- or 64-bit signed integers, unsigned integer, floating point numbers or to STL containers consisting of elements of such type. If we want to use custom container types and/or custom insertion routines, we have to use `.bind_container(container&, inserter)` which accepts a binary function with the signature `inserter(container_t&, container_t::value_type const&)` (up to implicit conversion). ```cpp #include @@ -335,35 +335,35 @@ We may bind options to variables of type `std::string`, to 32- or 64-bit signed #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; std::uint32_t optimization = 0; // the value we set here acts as an implicit fallback - parser[ "optimization" ] - .abbreviation( 'O' ) - .description( "set the optimization level (default: -O0)" ) - .bind( optimization ); // write the parsed value to the variable 'optimization' - // .bind( optimization ) automatically calls .type( po::u32 ) and .single() - - std::vector< std::string > include_paths; - parser[ "include-path" ] - .abbreviation( 'I' ) - .description( "add an include path" ) - .bind( include_paths ); // append paths to the vector 'include_paths' - - parser[ "help" ] - .abbreviation( '?' ) - .description( "print this help screen" ); - - std::deque< std::string > files; - parser[ "" ] - .bind( files ); // append paths to the deque 'include_paths - - if( !parser( argc, argv ) ) + parser["optimization"] + .abbreviation('O') + .description("set the optimization level (default: -O0)") + .bind(optimization); // write the parsed value to the variable 'optimization' + // .bind(optimization) automatically calls .type(po::u32) and .single() + + std::vector include_paths; + parser["include-path"] + .abbreviation('I') + .description("add an include path") + .bind(include_paths); // append paths to the vector 'include_paths' + + parser["help"] + .abbreviation('?') + .description("print this help screen"); + + std::deque files; + parser[""] + .bind(files); // append paths to the deque 'include_paths + + if(!parser(argc, argv)) return -1; // we don't want to print anything else if the help screen has been displayed - if( parser[ "help" ].was_set() ) { + if(parser["help"].was_set()) { std::cout << parser << '\n'; return 0; } @@ -372,10 +372,10 @@ int main( int argc, char** argv ) { // note that we don't need to access parser anymore; all data is stored in the bound variables std::cout << "optimization level = " << optimization << '\n'; std::cout << "include files (" << files.size() << "):\n"; - for( auto&& i : files ) + for(auto&& i : files) std::cout << '\t' << i << '\n'; std::cout << "include paths (" << include_paths.size() << "):\n"; - for( auto&& i : include_paths ) + for(auto&& i : include_paths) std::cout << '\t' << i << '\n'; } ``` diff --git a/examples/1 optimization.cxx b/examples/1 optimization.cxx index edc13a5..f39534a 100644 --- a/examples/1 optimization.cxx +++ b/examples/1 optimization.cxx @@ -1,16 +1,16 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] // corresponds to --optimization - .abbreviation( 'O' ) // corresponds to -O - .type( po::u32 ); // expects an unsigned 32-bit integer + parser["optimization"] // corresponds to --optimization + .abbreviation('O') // corresponds to -O + .type(po::u32); // expects an unsigned 32-bit integer - parser( argc, argv ); // parses the command line arguments + parser(argc, argv); // parses the command line arguments - auto&& O = parser[ "optimization" ]; - if( !O.available() ) + auto&& O = parser["optimization"]; + if(!O.available()) std::cout << "no optimization level set!\n"; else std::cout << "optimization level set to " << O.get().u32 << '\n'; diff --git a/examples/2 include.cxx b/examples/2 include.cxx index d6b466e..a847225 100644 --- a/examples/2 include.cxx +++ b/examples/2 include.cxx @@ -1,29 +1,29 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] // corresponds to --optimization - .abbreviation( 'O' ) // corresponds to -O - .type( po::u32 ) // expects an unsigned 32-bit integer - .fallback( 0 ); // if --optimization is not explicitly specified, assume 0 + parser["optimization"] // corresponds to --optimization + .abbreviation('O') // corresponds to -O + .type(po::u32) // expects an unsigned 32-bit integer + .fallback(0); // if --optimization is not explicitly specified, assume 0 - parser[ "include-path" ] // corresponds to --include-path - .abbreviation( 'I' ) // corresponds to -I - .type( po::string ) // expects a string - .multi(); // allows multiple arguments for the same option + parser["include-path"] // corresponds to --include-path + .abbreviation('I') // corresponds to -I + .type(po::string) // expects a string + .multi(); // allows multiple arguments for the same option - parser( argc, argv ); // parses the command line arguments + parser(argc, argv); // parses the command line arguments - auto&& O = parser[ "optimization" ]; + auto&& O = parser["optimization"]; // .was_set() reports whether the option was specified by the user or relied on the predefined fallback value. - std::cout << "optimization level (" << ( O.was_set() ? "manual" : "auto" ) << ") = " << O.get().u32 << '\n'; + std::cout << "optimization level (" << (O.was_set() ? "manual" : "auto") << ") = " << O.get().u32 << '\n'; - auto&& I = parser[ "include-path" ]; + auto&& I = parser["include-path"]; // .size() and .count() return the number of given arguments. Without .multi(), their return value is always <= 1. std::cout << "include paths (" << I.size() << "):\n"; // Here, the non-template .begin() / .end() methods were used. Their value type is po::value, // which is not a value in itself but contains the desired values as members, i.e. i.string. - for( auto&& i : I ) + for(auto&& i : I) std::cout << '\t' << i.string << '\n'; } diff --git a/examples/3 files.cxx b/examples/3 files.cxx index 259aabe..7e051a1 100644 --- a/examples/3 files.cxx +++ b/examples/3 files.cxx @@ -1,55 +1,55 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - parser[ "optimization" ] // corresponds to --optimization - .abbreviation( 'O' ) // corresponds to -O - .description( "set the optimization level (default: -O0)" ) + parser["optimization"] // corresponds to --optimization + .abbreviation('O') // corresponds to -O + .description("set the optimization level (default: -O0)") // the description to be shown when printing the parser - .type( po::u32 ) // expects an unsigned 32-bit integer - .fallback( 0 ); // if --optimization is not explicitly specified, assume 0 + .type(po::u32) // expects an unsigned 32-bit integer + .fallback(0); // if --optimization is not explicitly specified, assume 0 - parser[ "include-path" ] // corresponds to --include-path - .abbreviation( 'I' ) // corresponds to -I - .description( "add an include path" ) - .type( po::string ) // expects a string + parser["include-path"] // corresponds to --include-path + .abbreviation('I') // corresponds to -I + .description("add an include path") + .type(po::string) // expects a string .multi(); // allows multiple arguments for the same option - parser[ "help" ] // corresponds to --help - .abbreviation( '?' ) // corresponds to -? - .description( "print this help screen" ) - // .type( po::void_ ) // redundant; default for named parameters + parser["help"] // corresponds to --help + .abbreviation('?') // corresponds to -? + .description("print this help screen") + // .type(po::void_) // redundant; default for named parameters // .single() // redundant; default for named parameters - .callback( [ & ]{ std::cout << parser << '\n'; } ); + .callback([&]{ std::cout << parser << '\n'; }); // callbacks get invoked when the option occurs - parser[ "" ] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c - // .type( po::string ) // redundant; default for the unnamed parameter + parser[""] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c + // .type(po::string) // redundant; default for the unnamed parameter // .multi() // redundant; default for the unnamed parameter - .callback( [ & ]( std::string const& x ){ std::cout << "processed \'" << x << "\' successfully!\n"; } ); + .callback([&](std::string const& x){ std::cout << "processed \'" << x << "\' successfully!\n"; }); // as .get_type() == po::string, the callback may take an std::string // parsing returns false if at least one error has occurred - if( !parser( argc, argv ) ) { + if(!parser(argc, argv)) { std::cerr << "errors occurred; aborting\n"; return -1; } // we don't want to print anything else if the help screen has been displayed - if( parser[ "help" ].size() ) + if(parser["help"].size()) return 0; - std::cout << "processed files: " << parser[ "" ].size() << '\n'; + std::cout << "processed files: " << parser[""].size() << '\n'; - auto&& O = parser[ "optimization" ]; + auto&& O = parser["optimization"]; // .was_set() reports whether the option was specified by the user or relied on the predefined fallback value. - std::cout << "optimization level (" << ( O.was_set() ? "manual" : "auto" ) << ") = " << O.get().u32 << '\n'; + std::cout << "optimization level (" << (O.was_set() ? "manual" : "auto") << ") = " << O.get().u32 << '\n'; - auto&& I = parser[ "include-path" ]; + auto&& I = parser["include-path"]; // .size() and .count() return the number of given arguments. Without .multi(), their return value is always <= 1. std::cout << "include paths (" << I.size() << "):\n"; // Here, the non-template .begin() / .end() methods were used. Their value type is // po::value, which is not a value in itself but contains the desired values as members, i.e. i.string. - for( auto&& i : I ) + for(auto&& i : I) std::cout << '\t' << i.string << '\n'; } diff --git a/examples/4 sum.cxx b/examples/4 sum.cxx index 0394dc1..4f61cdb 100644 --- a/examples/4 sum.cxx +++ b/examples/4 sum.cxx @@ -2,22 +2,22 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - auto&& x = parser[ "" ] // the unnamed parameter - .type( po::f64 ) // expects 64-bit floating point numbers + auto&& x = parser[""] // the unnamed parameter + .type(po::f64) // expects 64-bit floating point numbers .multi() // allows multiple arguments - .fallback( -8, "+.5e2" ) // if no arguments were provided, assume these as default - .callback( [ & ]{ std::cout << "successfully parsed "; } ) - .callback( [ & ]( std::string const& x ){ std::cout << x; } ) - .callback( [ & ]{ std::cout << " which equals "; } ) - .callback( [ & ]( po::f64_t x ){ std::cout << x << '\n'; } ); + .fallback(-8, "+.5e2") // if no arguments were provided, assume these as default + .callback([&]{ std::cout << "successfully parsed "; }) + .callback([&](std::string const& x){ std::cout << x; }) + .callback([&]{ std::cout << " which equals "; }) + .callback([&](po::f64_t x){ std::cout << x << '\n'; }); - parser( argc, argv ); + parser(argc, argv); - std::cout << "( + "; - for( auto&& i : x.to_vector< po::f64 >() ) // unnecessary copy; for demonstration purposes only + std::cout << "(+ "; + for(auto&& i : x.to_vector()) // unnecessary copy; for demonstration purposes only std::cout << i << ' '; - std::cout << ") = " << std::accumulate( x.begin< po::f64 >(), x.end< po::f64 >(), po::f64_t{} ) << '\n'; + std::cout << ") = " << std::accumulate(x.begin(), x.end(), po::f64_t{}) << '\n'; } diff --git a/examples/5 bind.cxx b/examples/5 bind.cxx index 6905ab7..e4ddd0c 100644 --- a/examples/5 bind.cxx +++ b/examples/5 bind.cxx @@ -5,36 +5,36 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; std::uint32_t optimization = 0; // the value we set here acts as an implicit fallback - parser[ "optimization" ] // corresponds to --optimization - .abbreviation( 'O' ) // corresponds to -O - .description( "set the optimization level (default: -O0)" ) - .bind( optimization ); // write the parsed value to the variable 'optimization' - // .bind( optimization ) automatically calls .type( po::u32 ) and .single() - - std::vector< std::string > include_paths; - parser[ "include-path" ] // corresponds to --include-path - .abbreviation( 'I' ) // corresponds to -I - .description( "add an include path" ) - .bind( include_paths ); // append paths to the vector 'include_paths' - - parser[ "help" ] // corresponds to --help - .abbreviation( '?' ) // corresponds to -? - .description( "print this help screen" ); - - std::deque< std::string > files; - parser[ "" ] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c - .bind( files ); // append paths to the deque 'include_paths + parser["optimization"] // corresponds to --optimization + .abbreviation('O') // corresponds to -O + .description("set the optimization level (default: -O0)") + .bind(optimization); // write the parsed value to the variable 'optimization' + // .bind(optimization) automatically calls .type(po::u32) and .single() + + std::vector include_paths; + parser["include-path"] // corresponds to --include-path + .abbreviation('I') // corresponds to -I + .description("add an include path") + .bind(include_paths); // append paths to the vector 'include_paths' + + parser["help"] // corresponds to --help + .abbreviation('?') // corresponds to -? + .description("print this help screen"); + + std::deque files; + parser[""] // the unnamed parameter is used for non-option arguments, i.e. gcc a.c b.c + .bind(files); // append paths to the deque 'include_paths // parsing returns false if at least one error has occurred - if( !parser( argc, argv ) ) + if(!parser(argc, argv)) return -1; // we don't want to print anything else if the help screen has been displayed - if( parser[ "help" ].was_set() ) { + if(parser["help"].was_set()) { std::cout << parser << '\n'; return 0; } @@ -44,10 +44,10 @@ int main( int argc, char** argv ) { std::cout << "optimization level = " << optimization << '\n'; std::cout << "include files (" << files.size() << "):\n"; - for( auto&& i : files ) + for(auto&& i : files) std::cout << '\t' << i << '\n'; std::cout << "include paths (" << include_paths.size() << "):\n"; - for( auto&& i : include_paths ) + for(auto&& i : include_paths) std::cout << '\t' << i << '\n'; } diff --git a/examples/colors.cxx b/examples/colors.cxx index 501b609..b736108 100644 --- a/examples/colors.cxx +++ b/examples/colors.cxx @@ -2,20 +2,20 @@ #include int main() { - std::cout << po::black << "black " << static_cast< int >( po::black ) << '\n'; - std::cout << po::maroon << "maroon " << static_cast< int >( po::maroon ) << '\n'; - std::cout << po::green << "green " << static_cast< int >( po::green ) << '\n'; - std::cout << po::brown << "brown " << static_cast< int >( po::brown ) << '\n'; - std::cout << po::navy << "navy " << static_cast< int >( po::navy ) << '\n'; - std::cout << po::purple << "purple " << static_cast< int >( po::purple ) << '\n'; - std::cout << po::teal << "teal " << static_cast< int >( po::teal ) << '\n'; - std::cout << po::light_gray << "light_gray " << static_cast< int >( po::light_gray ) << '\n'; - std::cout << po::dark_gray << "dark_gray " << static_cast< int >( po::dark_gray ) << '\n'; - std::cout << po::red << "red " << static_cast< int >( po::red ) << '\n'; - std::cout << po::lime << "lime " << static_cast< int >( po::lime ) << '\n'; - std::cout << po::yellow << "yellow " << static_cast< int >( po::yellow ) << '\n'; - std::cout << po::blue << "blue " << static_cast< int >( po::blue ) << '\n'; - std::cout << po::fuchsia << "fuchsia " << static_cast< int >( po::fuchsia ) << '\n'; - std::cout << po::cyan << "cyan " << static_cast< int >( po::cyan ) << '\n'; - std::cout << po::white << "white " << static_cast< int >( po::white ) << '\n'; + std::cout << po::black << "black " << static_cast(po::black ) << '\n'; + std::cout << po::maroon << "maroon " << static_cast(po::maroon ) << '\n'; + std::cout << po::green << "green " << static_cast(po::green ) << '\n'; + std::cout << po::brown << "brown " << static_cast(po::brown ) << '\n'; + std::cout << po::navy << "navy " << static_cast(po::navy ) << '\n'; + std::cout << po::purple << "purple " << static_cast(po::purple ) << '\n'; + std::cout << po::teal << "teal " << static_cast(po::teal ) << '\n'; + std::cout << po::light_gray << "light_gray " << static_cast(po::light_gray ) << '\n'; + std::cout << po::dark_gray << "dark_gray " << static_cast(po::dark_gray ) << '\n'; + std::cout << po::red << "red " << static_cast(po::red ) << '\n'; + std::cout << po::lime << "lime " << static_cast(po::lime ) << '\n'; + std::cout << po::yellow << "yellow " << static_cast(po::yellow ) << '\n'; + std::cout << po::blue << "blue " << static_cast(po::blue ) << '\n'; + std::cout << po::fuchsia << "fuchsia " << static_cast(po::fuchsia ) << '\n'; + std::cout << po::cyan << "cyan " << static_cast(po::cyan ) << '\n'; + std::cout << po::white << "white " << static_cast(po::white ) << '\n'; } diff --git a/examples/detect_type.cxx b/examples/detect_type.cxx index 3ecd181..9b97ac8 100644 --- a/examples/detect_type.cxx +++ b/examples/detect_type.cxx @@ -1,20 +1,20 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - auto&& o = parser[ "" ]; - parser( argc, argv ); + auto&& o = parser[""]; + parser(argc, argv); po::value_type testing_order[] = { po::void_, po::u32, po::u64, po::i32, po::i64, po::f32, po::f64, po::string }; // iterate over std::strings - for( auto iter = o.begin< po::string >(); iter != o.end< po::string >(); ++iter ) { + for(auto iter = o.begin(); iter != o.end(); ++iter) { std::cout << '\'' << *iter << "\' has type "; - for( auto&& type : testing_order ) + for(auto&& type : testing_order) // we try to parse the string with an option of the corresponding type - if( po::option{}.type( type ).parse( *iter ) == po::error_code::none ) { + if(po::option{}.type(type).parse(*iter) == po::error_code::none) { // if the conversion succeeds, print the type - std::cout << vt2str( type ); + std::cout << vt2str(type); break; } std::cout << '\n'; diff --git a/examples/flag.cxx b/examples/flag.cxx index 690f5cb..c7f2f97 100644 --- a/examples/flag.cxx +++ b/examples/flag.cxx @@ -1,12 +1,12 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - auto&& x = parser[ "x" ]; // creates an option with name 'x' + auto&& x = parser["x"]; // creates an option with name 'x' - parser( argc, argv ); // parses the command line arguments + parser(argc, argv); // parses the command line arguments - if( x.available() ) + if(x.available()) std::cout << "flag x set!\n"; } diff --git a/examples/getopt.cxx b/examples/getopt.cxx index 95e8b03..bc13f80 100644 --- a/examples/getopt.cxx +++ b/examples/getopt.cxx @@ -4,23 +4,23 @@ #include #include -int main( int argc, char** argv ) { +int main(int argc, char** argv) { po::parser parser; - auto&& a = parser[ "a" ]; - auto&& b = parser[ "b" ]; - auto&& c = parser[ "c" ] - .type( po::string ) - .fallback( "(null)" ); - auto&& unnamed = parser[ "" ] - .type( po::string ) + auto&& a = parser["a"]; + auto&& b = parser["b"]; + auto&& c = parser["c"] + .type(po::string) + .fallback("(null)"); + auto&& unnamed = parser[""] + .type(po::string) .multi(); - parser( argc, argv ); + parser(argc, argv); std::cout << "aflag = " << a.was_set() << ", "; std::cout << "bflag = " << b.was_set() << ", "; std::cout << "cflag = " << c.get().string << '\n'; - for( auto&& i : unnamed ) + for(auto&& i : unnamed) std::cout << "Non-option argument " << i.string << '\n'; } diff --git a/include/ProgramOptions.hxx b/include/ProgramOptions.hxx index 9535259..e07a9c9 100644 --- a/include/ProgramOptions.hxx +++ b/include/ProgramOptions.hxx @@ -41,25 +41,25 @@ #undef PROGRAMOPTIONS_ASSERT #ifdef NDEBUG - #define PROGRAMOPTIONS_ASSERT( Expression, Message ) + #define PROGRAMOPTIONS_ASSERT(Expression, Message) #else // NDEBUG #ifdef PROGRAMOPTIONS_NO_EXCEPTIONS - #define PROGRAMOPTIONS_ASSERT( Expression, Message ) assert( ( Expression ) && Message ); + #define PROGRAMOPTIONS_ASSERT(Expression, Message) assert((Expression) && Message); #else // PROGRAMOPTIONS_NO_EXCEPTIONS - #define PROGRAMOPTIONS_ASSERT( Expression, Message )\ + #define PROGRAMOPTIONS_ASSERT(Expression, Message)\ do {\ - if( !( Expression ) )\ - throw std::logic_error{ ( "ProgramOptions.hxx:" + std::to_string( __LINE__ ) + ": " ) + ( Message ) };\ - } while( 0 ) + if(!(Expression))\ + throw std::logic_error{ ("ProgramOptions.hxx:" + std::to_string(__LINE__) + ": ") + (Message) };\ + } while(0) #endif // PROGRAMOPTIONS_NO_EXCEPTIONS #endif // NDEBUG -#if defined( PROGRAMOPTIONS_WINDOWS ) && defined( PROGRAMOPTIONS_ANSI ) +#if defined(PROGRAMOPTIONS_WINDOWS) && defined(PROGRAMOPTIONS_ANSI) #error Please define either PROGRAMOPTIONS_WINDOWS or PROGRAMOPTIONS_ANSI #endif -#if !defined( PROGRAMOPTIONS_NO_COLORS ) && !defined( PROGRAMOPTIONS_WINDOWS ) && !defined( PROGRAMOPTIONS_ANSI ) - #if defined( WIN32 ) || defined( _WIN32 ) || defined( _WIN64 ) || defined( __WIN32__ ) || defined( __TOS_WIN__ ) || defined( __WINDOWS__ ) +#if !defined(PROGRAMOPTIONS_NO_COLORS) && !defined(PROGRAMOPTIONS_WINDOWS) && !defined(PROGRAMOPTIONS_ANSI) + #if defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) #define PROGRAMOPTIONS_WINDOWS #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 @@ -99,7 +99,7 @@ namespace po { }; #ifndef PROGRAMOPTIONS_NO_COLORS class color_resetter; - color_resetter operator<<( std::ostream& stream, color_t color ); + color_resetter operator<<(std::ostream& stream, color_t color); class color_resetter { std::ostream& m_stream; @@ -108,37 +108,37 @@ namespace po { WORD m_old_attributes; #endif // PROGRAMOPTIONS_WINDOWS - color_resetter( std::ostream& stream, color_t color ) + color_resetter(std::ostream& stream, color_t color) : m_stream(stream) { // don't use an initializer list here because of gcc-4.8.5 #ifdef PROGRAMOPTIONS_WINDOWS m_stream << std::flush; - m_console = GetStdHandle( STD_OUTPUT_HANDLE ); - assert( m_console != INVALID_HANDLE_VALUE ); + m_console = GetStdHandle(STD_OUTPUT_HANDLE); + assert(m_console != INVALID_HANDLE_VALUE); CONSOLE_SCREEN_BUFFER_INFO info; - const BOOL result = GetConsoleScreenBufferInfo( m_console, &info ); - assert( result ); - ( void )result; + const BOOL result = GetConsoleScreenBufferInfo(m_console, &info); + assert(result); + (void)result; m_old_attributes = info.wAttributes; WORD attribute = 0; - if( color < 0 ) { - color = static_cast< color_t >( -color ); + if(color < 0) { + color = static_cast(-color); attribute |= FOREGROUND_INTENSITY; } - if( color == maroon || color == brown || color == purple || color == light_gray ) + if(color == maroon || color == brown || color == purple || color == light_gray) attribute |= FOREGROUND_RED; - if( color == green || color == brown || color == teal || color == light_gray ) + if(color == green || color == brown || color == teal || color == light_gray) attribute |= FOREGROUND_GREEN; - if( color == navy || color == purple || color == teal || color == light_gray ) + if(color == navy || color == purple || color == teal || color == light_gray) attribute |= FOREGROUND_BLUE; - SetConsoleTextAttribute( m_console, attribute ); + SetConsoleTextAttribute(m_console, attribute); #endif // PROGRAMOPTIONS_WINDOWS #ifdef PROGRAMOPTIONS_ANSI m_stream << "\x1B["; - if( color < 0 ) { - color = static_cast< color_t >( -color ); + if(color < 0) { + color = static_cast(-color); m_stream << "1;"; } - m_stream << static_cast< int >( color ) << 'm'; + m_stream << static_cast(color) << 'm'; #endif // PROGRAMOPTIONS_ANSI } @@ -146,7 +146,7 @@ namespace po { ~color_resetter() { #ifdef PROGRAMOPTIONS_WINDOWS m_stream << std::flush; - SetConsoleTextAttribute( m_console, m_old_attributes ); + SetConsoleTextAttribute(m_console, m_old_attributes); #endif // PROGRAMOPTIONS_WINDOWS #ifdef PROGRAMOPTIONS_ANSI m_stream << "\x1B[0m"; @@ -156,24 +156,24 @@ namespace po { operator std::ostream&() const { return m_stream; } - template< typename T > - std::ostream& operator<<( T&& arg ) { - return m_stream << std::forward< T >( arg ); + template + std::ostream& operator<<(T&& arg) { + return m_stream << std::forward(arg); } - friend color_resetter operator<<( std::ostream& stream, color_t color ); + friend color_resetter operator<<(std::ostream& stream, color_t color); }; - inline color_resetter operator<<( std::ostream& stream, color_t color ) { + inline color_resetter operator<<(std::ostream& stream, color_t color) { return { stream, color }; } #else // !PROGRAMOPTIONS_NO_COLORS - inline std::ostream& operator<<( std::ostream& stream, color_t /* color */ ) { // -Wunused-parameter + inline std::ostream& operator<<(std::ostream& stream, color_t /* color */) { // -Wunused-parameter return stream; } #endif // !PROGRAMOPTIONS_NO_COLORS struct error_t { - friend std::ostream& operator<<( std::ostream& stream, error_t const& /* object */ ) { // -Wunused-parameter + friend std::ostream& operator<<(std::ostream& stream, error_t const& /* object */) { // -Wunused-parameter return stream << red << "error: "; } }; @@ -184,104 +184,104 @@ namespace po { struct suggestion_t { std::string const& what; - friend std::ostream& operator<<( std::ostream& stream, suggestion_t const& object ) { + friend std::ostream& operator<<(std::ostream& stream, suggestion_t const& object) { stream << "; did you mean \'"; stream << white << object.what; stream << "\'?"; return stream; } }; - inline suggestion_t suggest( std::string const& what ) { + inline suggestion_t suggest(std::string const& what) { return { what }; } - template< typename arg_t > + template struct ignore_t { arg_t const& arg; - friend std::ostream& operator<<( std::ostream& stream, ignore_t const& object ) { + friend std::ostream& operator<<(std::ostream& stream, ignore_t const& object) { stream << "; ignoring \'"; stream << white << object.arg; stream << '\''; return stream; } }; - template< typename arg_t > - ignore_t< arg_t > ignoring( arg_t const& arg ) { + template + ignore_t ignoring(arg_t const& arg) { return { arg }; } // Compatibility stuff for the lack of C++14 support - template< typename T, typename... args_t > - std::unique_ptr< T > make_unique( args_t&&... args ) { - return std::unique_ptr< T >{ new T{ std::forward< args_t >( args )... } }; + template + std::unique_ptr make_unique(args_t&&... args) { + return std::unique_ptr{ new T{ std::forward(args)... } }; } - template< typename T, T... i > + template struct integer_sequence { using value_type = T; - static constexpr std::size_t size = sizeof...( i ); + static constexpr std::size_t size = sizeof...(i); }; namespace detail { - template< typename T, T i, bool _0 = ( i == 0 ), bool _1 = ( i == 1 ) > + template struct make_integer_sequence_impl; - template< typename T, T i, typename = typename make_integer_sequence_impl< T, i / 2 >::type, typename = typename make_integer_sequence_impl< T, i % 2 >::type > + template::type, typename = typename make_integer_sequence_impl::type > struct integer_sequence_assembler { }; - template< typename T, T i, T... j, T... k > - struct integer_sequence_assembler< T, i, integer_sequence< T, j... >, integer_sequence< T, k... > > { - using type = integer_sequence< T, j..., ( j + i / 2 )..., ( k + i - 1 )... >; + template + struct integer_sequence_assembler, integer_sequence> { + using type = integer_sequence; }; - template< typename T, T i > - struct make_integer_sequence_impl< T, i, true, false > { - using type = integer_sequence< T >; + template + struct make_integer_sequence_impl { + using type = integer_sequence; }; - template< typename T, T i > - struct make_integer_sequence_impl< T, i, false, true > { - using type = integer_sequence< T, 0 >; + template + struct make_integer_sequence_impl { + using type = integer_sequence; }; - template< typename T, T i > - struct make_integer_sequence_impl< T, i, false, false > { - static_assert( i >= 0, "make_integer_sequence requires a non-negative size" ); - using type = typename integer_sequence_assembler< T, i >::type; + template + struct make_integer_sequence_impl { + static_assert(i >= 0, "make_integer_sequence requires a non-negative size"); + using type = typename integer_sequence_assembler::type; }; } - template< typename T, T N > - using make_integer_sequence = typename detail::make_integer_sequence_impl< T, N >::type; - template< std::size_t N > - using make_index_sequence = make_integer_sequence< std::size_t, N >; + template + using make_integer_sequence = typename detail::make_integer_sequence_impl::type; + template + using make_index_sequence = make_integer_sequence; // End of compatibility stuff - inline bool case_insensitive_eq( char x, char y ) { - PROGRAMOPTIONS_ASSERT( x >= 0 && y >= 0, "case_insensitive_eq: arguments must be representable as unsigned char" ); - return x == y || std::tolower( x ) == std::tolower( y ); + inline bool case_insensitive_eq(char x, char y) { + PROGRAMOPTIONS_ASSERT(x >= 0 && y >= 0, "case_insensitive_eq: arguments must be representable as unsigned char"); + return x == y || std::tolower(x) == std::tolower(y); } - inline std::size_t damerau_levenshtein( char const* a, char const* b, std::size_t i, std::size_t j, std::size_t cutoff = std::numeric_limits< std::size_t >::max(), std::size_t distance = 0 ) { - if( distance >= cutoff ) + inline std::size_t damerau_levenshtein(char const* a, char const* b, std::size_t i, std::size_t j, std::size_t cutoff = std::numeric_limits::max(), std::size_t distance = 0) { + if(distance >= cutoff) return cutoff; - if( i == 0 ) + if(i == 0) return j; - if( j == 0 ) + if(j == 0) return i; std::size_t result = std::min( std::min( - damerau_levenshtein( a, b, i - 1, j, cutoff, distance + 1 ), - damerau_levenshtein( a, b, i, j - 1, cutoff, distance + 1 ) + damerau_levenshtein(a, b, i - 1, j, cutoff, distance + 1), + damerau_levenshtein(a, b, i, j - 1, cutoff, distance + 1) ), - damerau_levenshtein( a, b, i - 1, j - 1, cutoff, distance + !case_insensitive_eq( a[ i - 1 ], b[ j - 1 ] ) ) + damerau_levenshtein(a, b, i - 1, j - 1, cutoff, distance + !case_insensitive_eq(a[i - 1], b[j - 1])) ); - if( i >= 2 && j >= 2 && case_insensitive_eq( a[ i - 1 ], b[ j - 2 ] ) && case_insensitive_eq( a[ i - 2 ], b[ j - 1 ] ) ) - result = std::min( result, damerau_levenshtein( a, b, i - 2, j - 2, cutoff, distance + 1 ) ); + if(i >= 2 && j >= 2 && case_insensitive_eq(a[i - 1], b[j - 2]) && case_insensitive_eq(a[i - 2], b[j - 1])) + result = std::min(result, damerau_levenshtein(a, b, i - 2, j - 2, cutoff, distance + 1)); return result; } - inline std::size_t damerau_levenshtein( char const* a, char const* b, std::size_t cutoff = std::numeric_limits< std::size_t >::max() ) { - return damerau_levenshtein( a, b, std::strlen( a ), std::strlen( b ), cutoff ); + inline std::size_t damerau_levenshtein(char const* a, char const* b, std::size_t cutoff = std::numeric_limits::max()) { + return damerau_levenshtein(a, b, std::strlen(a), std::strlen(b), cutoff); } - inline std::size_t damerau_levenshtein( std::string a, std::string b, std::size_t cutoff = std::numeric_limits< std::size_t >::max() ) { - return damerau_levenshtein( a.c_str(), b.c_str(), a.size(), b.size(), cutoff ); + inline std::size_t damerau_levenshtein(std::string a, std::string b, std::size_t cutoff = std::numeric_limits::max()) { + return damerau_levenshtein(a.c_str(), b.c_str(), a.size(), b.size(), cutoff); } class repeat { @@ -289,19 +289,19 @@ namespace po { char m_character; public: - explicit repeat( std::size_t count, char character ) + explicit repeat(std::size_t count, char character) : m_count{ count }, m_character{ character } { } - friend std::ostream& operator<<( std::ostream& stream, repeat const& object ) { - std::fill_n( std::ostreambuf_iterator< char >( stream ), object.m_count, object.m_character ); + friend std::ostream& operator<<(std::ostream& stream, repeat const& object) { + std::fill_n(std::ostreambuf_iterator(stream), object.m_count, object.m_character); return stream; } }; - template< typename enum_t > - typename std::underlying_type< enum_t >::type enum2int( enum_t value ) { - return static_cast< typename std::underlying_type< enum_t >::type >( value ); + template + typename std::underlying_type::type enum2int(enum_t value) { + return static_cast::type>(value); } enum value_type { @@ -324,8 +324,8 @@ namespace po { "f32", "f64" }; - inline char const* vt2str( value_type type ) { - return value_type_strings[ enum2int( type ) ]; + inline char const* vt2str(value_type type) { + return value_type_strings[enum2int(type)]; } using void_t = void; @@ -338,103 +338,103 @@ namespace po { using f64_t = double; namespace detail { - template< value_type type > + template struct vt2type_impl { }; template<> - struct vt2type_impl< void_ > { using type = void_t; }; + struct vt2type_impl { using type = void_t; }; template<> - struct vt2type_impl< string > { using type = string_t; }; + struct vt2type_impl { using type = string_t; }; template<> - struct vt2type_impl< i32 > { using type = i32_t; }; + struct vt2type_impl { using type = i32_t; }; template<> - struct vt2type_impl< i64 > { using type = i64_t; }; + struct vt2type_impl { using type = i64_t; }; template<> - struct vt2type_impl< u32 > { using type = u32_t; }; + struct vt2type_impl { using type = u32_t; }; template<> - struct vt2type_impl< u64 > { using type = u64_t; }; + struct vt2type_impl { using type = u64_t; }; template<> - struct vt2type_impl< f32 > { using type = f32_t; }; + struct vt2type_impl { using type = f32_t; }; template<> - struct vt2type_impl< f64 > { using type = f64_t; }; + struct vt2type_impl { using type = f64_t; }; } - template< value_type type > - using vt2type = typename detail::vt2type_impl< type >::type; + template + using vt2type = typename detail::vt2type_impl::type; namespace detail { template< typename T, - bool is_integral = std::is_integral< T >::value, - bool is_floating_point = std::is_floating_point< T >::value, - bool is_signed = std::numeric_limits< T >::is_signed + bool is_integral = std::is_integral::value, + bool is_floating_point = std::is_floating_point::value, + bool is_signed = std::numeric_limits::is_signed > struct type2vt_impl { // Not using false because then it would trigger without instatiation. // Instead, use an expression that always evaluates to false but depends on T. - static_assert( !std::is_same< T, T >::value, "type2vt: unsupported type" ); + static_assert(!std::is_same::value, "type2vt: unsupported type"); static constexpr value_type value = void_; }; template<> - struct type2vt_impl< void, false, false, false > { + struct type2vt_impl { static constexpr value_type value = void_; }; template<> - struct type2vt_impl< std::string, false, false, false > { + struct type2vt_impl { static constexpr value_type value = string; }; - template< typename T > - struct type2vt_impl< T, true, false, true > { - static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits; - static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide signed integral types supported" ); - static constexpr value_type value = ( T_bits == 32 ) ? i32 : i64; + template + struct type2vt_impl { + static constexpr std::size_t T_bits = sizeof(T) * std::numeric_limits::digits; + static_assert(T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide signed integral types supported"); + static constexpr value_type value = (T_bits == 32) ? i32 : i64; }; - template< typename T > - struct type2vt_impl< T, true, false, false > { - static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits; - static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide unsigned integral types supported" ); - static constexpr value_type value = ( T_bits == 32 ) ? u32 : u64; + template + struct type2vt_impl { + static constexpr std::size_t T_bits = sizeof(T) * std::numeric_limits::digits; + static_assert(T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide unsigned integral types supported"); + static constexpr value_type value = (T_bits == 32) ? u32 : u64; }; - template< typename T > - struct type2vt_impl< T, false, true, true > { - static constexpr std::size_t T_bits = sizeof( T ) * std::numeric_limits< unsigned char >::digits; - static_assert( T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide floating point types supported" ); - static constexpr value_type value = ( T_bits == 32 ) ? f32 : f64; + template + struct type2vt_impl { + static constexpr std::size_t T_bits = sizeof(T) * std::numeric_limits::digits; + static_assert(T_bits == 32 || T_bits == 64, "type2vt: only 32 or 64 bit wide floating point types supported"); + static constexpr value_type value = (T_bits == 32) ? f32 : f64; }; } - template< typename T > - struct type2vt : detail::type2vt_impl< typename std::remove_cv< T >::type > { + template + struct type2vt : detail::type2vt_impl::type> { }; - template< typename T > - T pow( T base, unsigned exp ) { - if( exp == 0 ) + template + T pow(T base, unsigned exp) { + if(exp == 0) return 1; - T result = pow( base, exp / 2 ); + T result = pow(base, exp / 2); result *= result; - if( exp % 2 ) + if(exp % 2) result *= base; return result; } - template< typename T > - T pow( T base, int exp ) { - const T result = pow( base, static_cast< unsigned >( std::abs( exp ) ) ); + template + T pow(T base, int exp) { + const T result = pow(base, static_cast(std::abs(exp))); return exp >= 0 ? result : T{ 1 } / result; } - template< typename T, unsigned i > - struct pow10 : public std::integral_constant< T, 10 * pow10< T, i - 1 >::value > { + template + struct pow10 : public std::integral_constant::value> { }; - template< typename T > - struct pow10< T, 0 > : public std::integral_constant< T, 1 > { + template + struct pow10 : public std::integral_constant { }; - template< unsigned i, bool = ( i < 10 ) > - struct log10 : public std::integral_constant< unsigned, 1 + log10< i / 10 >::value > { + template + struct log10 : public std::integral_constant::value> { }; template<> - struct log10< 0, true >; - template< unsigned i > - struct log10< i, true > : public std::integral_constant< unsigned, 0 > { + struct log10<0, true>; + template + struct log10 : public std::integral_constant { }; enum class error_code { @@ -445,20 +445,20 @@ namespace po { out_of_range }; - template< typename T > + template struct parsing_report { error_code error = error_code::none; const T value{}; parsing_report() = default; - parsing_report( error_code error ) + parsing_report(error_code error) : error{ error } { } - parsing_report( T const& value ) + parsing_report(T const& value) : value{ value } { } - parsing_report( T&& value ) - : value{ std::move( value ) } { + parsing_report(T&& value) + : value{ std::move(value) } { } bool good() const { @@ -469,7 +469,7 @@ namespace po { } T const& get() const { - PROGRAMOPTIONS_ASSERT( good(), "parsing_report: cannot access data of an erroneous report" ); + PROGRAMOPTIONS_ASSERT(good(), "parsing_report: cannot access data of an erroneous report"); return value; } operator T const&() const { @@ -477,251 +477,251 @@ namespace po { } }; - inline bool is_bin_digit( char c ) { + inline bool is_bin_digit(char c) { return c == '0' || c == '1'; } - inline bool is_digit( char c ) { + inline bool is_digit(char c) { return '0' <= c && c <= '9'; } - inline bool is_hex_digit( char c ) { - return ( '0' <= c && c <= '9' ) || ( 'a' <= c && c <= 'f' ) || ( 'A' <= c && c <= 'F' ); + inline bool is_hex_digit(char c) { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); } - inline int get_bin_digit( char c ) { - if( is_bin_digit( c ) ) + inline int get_bin_digit(char c) { + if(is_bin_digit(c)) return c - '0'; else return -1; } - inline int get_digit( char c ) { - if( is_digit( c ) ) + inline int get_digit(char c) { + if(is_digit(c)) return c - '0'; else return -1; } - inline int get_hex_digit( char c ) { - if( '0' <= c && c <= '9' ) + inline int get_hex_digit(char c) { + if('0' <= c && c <= '9') return c - '0'; - else if( 'a' <= c && c <= 'f' ) + else if('a' <= c && c <= 'f') return 10 + c - 'a'; - else if( 'A' <= c && c <= 'F' ) + else if('A' <= c && c <= 'F') return 10 + c - 'A'; else return -1; } namespace detail { - template< typename forward_iterator_t > - bool expect_impl( forward_iterator_t /* first */, forward_iterator_t /* last */ ) { // -Wunused-parameter + template + bool expect_impl(forward_iterator_t /* first */, forward_iterator_t /* last */) { // -Wunused-parameter return true; } - template< typename forward_iterator_t, typename... tail_t > - bool expect_impl( forward_iterator_t& first, forward_iterator_t last, char head, tail_t const&... tail ) { - return first != last && case_insensitive_eq( *first, head ) && expect_impl( ++first, last, tail... ); + template + bool expect_impl(forward_iterator_t& first, forward_iterator_t last, char head, tail_t const&... tail) { + return first != last && case_insensitive_eq(*first, head) && expect_impl(++first, last, tail...); } } - template< typename forward_iterator_t, typename... args_t > - bool expect( forward_iterator_t& first, forward_iterator_t last, args_t&&... args ) { + template + bool expect(forward_iterator_t& first, forward_iterator_t last, args_t&&... args) { forward_iterator_t first_copy{ first }; - const bool result = detail::expect_impl( first_copy, last, std::forward< args_t >( args )... ); - if( result ) + const bool result = detail::expect_impl(first_copy, last, std::forward(args)...); + if(result) first = first_copy; return result; } namespace detail { - template< typename forward_iterator_t, std::size_t N, std::size_t... indices > - bool expect_unpacker( forward_iterator_t& first, forward_iterator_t last, const char( &args )[ N ], integer_sequence< std::size_t, indices... > ) { - return expect( first, last, args[ indices ]... ); + template + bool expect_unpacker(forward_iterator_t& first, forward_iterator_t last, const char(&args)[N], integer_sequence) { + return expect(first, last, args[indices]...); } } - template< typename forward_iterator_t, std::size_t N > - bool expect( forward_iterator_t& first, forward_iterator_t last, const char( &args )[ N ] ) { - return detail::expect_unpacker( first, last, args, make_index_sequence< N - 1 >{} ); + template + bool expect(forward_iterator_t& first, forward_iterator_t last, const char(&args)[N]) { + return detail::expect_unpacker(first, last, args, make_index_sequence{}); } - template< typename T, typename forward_iterator_t > - parsing_report< T > str2uint( forward_iterator_t first, forward_iterator_t last ) { - static_assert( std::numeric_limits< T >::is_integer && !std::numeric_limits< T >::is_signed, "str2uint only supports unsigned integral types" ); - static_assert( std::numeric_limits< T >::digits % 4 == 0, "type doesn't meet requirements" ); + template + parsing_report str2uint(forward_iterator_t first, forward_iterator_t last) { + static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, "str2uint only supports unsigned integral types"); + static_assert(std::numeric_limits::digits % 4 == 0, "type doesn't meet requirements"); - for( ; first != last && std::isspace( *first ); ++first ); - expect( first, last, '+' ); - if( first == last || !is_digit( *first ) ) + for(; first != last && std::isspace(*first); ++first); + expect(first, last, '+'); + if(first == last || !is_digit(*first)) return error_code::conversion_error; - for( ; first != last && *first == '0'; ++first ); + for(; first != last && *first == '0'; ++first); T result{}; - if( first == last ) + if(first == last) return result; - if( expect( first, last, 'x' ) ) { - if( first == last || !is_hex_digit( *first ) ) + if(expect(first, last, 'x')) { + if(first == last || !is_hex_digit(*first)) return error_code::conversion_error; - for( ; first != last && *first == '0'; ++first ); + for(; first != last && *first == '0'; ++first); std::size_t digits = 0; enum : std::size_t { - max_digits = std::numeric_limits< T >::digits / 4 + max_digits = std::numeric_limits::digits / 4 }; - for( int d{}; first != last && digits <= max_digits && ( d = get_hex_digit( *first ) ) >= 0; ++first, ++digits ) - ( result <<= 4 ) |= d; - if( digits > max_digits ) + for(int d{}; first != last && digits <= max_digits && (d = get_hex_digit(*first)) >= 0; ++first, ++digits) + (result <<= 4) |= d; + if(digits > max_digits) return error_code::out_of_range; // TODO: exponents for hex ints with pP? - } else if( expect( first, last, 'b' ) ) { - if( first == last || !is_bin_digit( *first ) ) + } else if(expect(first, last, 'b')) { + if(first == last || !is_bin_digit(*first)) return error_code::conversion_error; - for( ; first != last && *first == '0'; ++first ); + for(; first != last && *first == '0'; ++first); std::size_t digits = 0; enum : std::size_t { - max_digits = std::numeric_limits< T >::digits + max_digits = std::numeric_limits::digits }; - for( int d{}; first != last && digits <= max_digits && ( d = get_bin_digit( *first ) ) >= 0; ++first, ++digits ) - ( result <<= 1 ) |= d; - if( digits > max_digits ) + for(int d{}; first != last && digits <= max_digits && (d = get_bin_digit(*first)) >= 0; ++first, ++digits) + (result <<= 1) |= d; + if(digits > max_digits) return error_code::out_of_range; } else { std::size_t decimals = 0; enum : std::size_t { - max_decimals = 1 + std::numeric_limits< T >::digits10 + max_decimals = 1 + std::numeric_limits::digits10 }; - for( int d{}; first != last && decimals <= max_decimals && ( d = get_digit( *first ) ) >= 0; ++first, ++decimals ) - result = 10 * result + static_cast< T >( d ); - if( decimals >= max_decimals ) - if( decimals > max_decimals || ( result < pow10< T, max_decimals - 1 >::value ) ) + for(int d{}; first != last && decimals <= max_decimals && (d = get_digit(*first)) >= 0; ++first, ++decimals) + result = 10 * result + static_cast(d); + if(decimals >= max_decimals) + if(decimals > max_decimals || (result < pow10::value)) return error_code::out_of_range; - if( expect( first, last, 'e' ) ) { - expect( first, last, '+' ); - if( first == last || !is_digit( *first ) ) + if(expect(first, last, 'e')) { + expect(first, last, '+'); + if(first == last || !is_digit(*first)) return error_code::conversion_error; - for( ; first != last && *first == '0'; ++first ); + for(; first != last && *first == '0'; ++first); unsigned exp{}; std::size_t decimals = 0; enum : std::size_t { - max = std::numeric_limits< T >::digits10, - max_decimals = log10< max >::value + 1 + max = std::numeric_limits::digits10, + max_decimals = log10::value + 1 }; - for( int d{}; first != last && decimals <= max_decimals && ( d = get_digit( *first ) ) >= 0; ++first, ++decimals ) - exp = 10 * exp + static_cast< unsigned >( d ); - if( decimals >= max_decimals ) - if( decimals > max_decimals || exp > max ) + for(int d{}; first != last && decimals <= max_decimals && (d = get_digit(*first)) >= 0; ++first, ++decimals) + exp = 10 * exp + static_cast(d); + if(decimals >= max_decimals) + if(decimals > max_decimals || exp > max) return error_code::out_of_range; - const T fac = pow( T{ 10 }, exp ); + const T fac = pow(T{ 10 }, exp); const T mant = result; result *= fac; - if( result / fac != mant ) + if(result / fac != mant) return error_code::out_of_range; } } - for( ; first != last && std::isspace( *first ); ++first ); - if( first != last ) + for(; first != last && std::isspace(*first); ++first); + if(first != last) return error_code::conversion_error; return result; } - template< typename T > - parsing_report< T > str2uint( std::string const& str ) { - return str2uint< T >( str.begin(), str.end() ); + template + parsing_report str2uint(std::string const& str) { + return str2uint(str.begin(), str.end()); } - template< typename T > - parsing_report< T > str2uint( char const* str ) { - return str2uint< T >( str, str + std::strlen( str ) ); + template + parsing_report str2uint(char const* str) { + return str2uint(str, str + std::strlen(str)); } - template< typename T, typename forward_iterator_t > - parsing_report< T > str2int( forward_iterator_t first, forward_iterator_t last ) { - static_assert( std::numeric_limits< T >::is_integer && std::numeric_limits< T >::is_signed, "str2uint only supports signed integral types" ); + template + parsing_report str2int(forward_iterator_t first, forward_iterator_t last) { + static_assert(std::numeric_limits::is_integer && std::numeric_limits::is_signed, "str2uint only supports signed integral types"); - for( ; first != last && std::isspace( *first ); ++first ); - const bool neg = expect( first, last, '-' ); - if( !neg ) - expect( first, last, '+' ); - if( first == last || !is_digit( *first ) ) + for(; first != last && std::isspace(*first); ++first); + const bool neg = expect(first, last, '-'); + if(!neg) + expect(first, last, '+'); + if(first == last || !is_digit(*first)) return error_code::conversion_error; - using unsigned_t = typename std::make_unsigned< T >::type; - const auto report = str2uint< unsigned_t >( first, last ); - if( !report ) + using unsigned_t = typename std::make_unsigned::type; + const auto report = str2uint(first, last); + if(!report) return report.error; - unsigned_t max = neg ? static_cast< unsigned_t >( -std::numeric_limits< T >::min() ) : static_cast< unsigned_t >( std::numeric_limits< T >::max() ); - if( report > max ) + unsigned_t max = neg ? static_cast(-std::numeric_limits::min()) : static_cast(std::numeric_limits::max()); + if(report > max) return error_code::out_of_range; - return neg ? -static_cast< T >( report ) : static_cast< T >( report ); + return neg ? -static_cast(report) : static_cast(report); } - template< typename T > - parsing_report< T > str2int( std::string const& str ) { - return str2int< T >( str.begin(), str.end() ); + template + parsing_report str2int(std::string const& str) { + return str2int(str.begin(), str.end()); } - template< typename T > - parsing_report< T > str2int( char const* str ) { - return str2int< T >( str, str + std::strlen( str ) ); + template + parsing_report str2int(char const* str) { + return str2int(str, str + std::strlen(str)); } - template< typename T, typename forward_iterator_t > - parsing_report< T > str2flt( forward_iterator_t first, forward_iterator_t last ) { - static_assert( std::is_floating_point< T >::value, "str2flt only supports built-in floating point types" ); - static_assert( std::numeric_limits< T >::is_iec559, "platform doesn't meet requirements" ); - static_assert( std::numeric_limits< T >::has_quiet_NaN, "type insufficient; doesn't support quiet NaNs" ); - static_assert( std::numeric_limits< T >::has_infinity, "type insufficient; doesn't support infinities" ); - - for( ; first != last && std::isspace( *first ); ++first ); - const bool neg = expect( first, last, '-' ); - if( !neg ) - expect( first, last, '+' ); + template + parsing_report str2flt(forward_iterator_t first, forward_iterator_t last) { + static_assert(std::is_floating_point::value, "str2flt only supports built-in floating point types"); + static_assert(std::numeric_limits::is_iec559, "platform doesn't meet requirements"); + static_assert(std::numeric_limits::has_quiet_NaN, "type insufficient; doesn't support quiet NaNs"); + static_assert(std::numeric_limits::has_infinity, "type insufficient; doesn't support infinities"); + + for(; first != last && std::isspace(*first); ++first); + const bool neg = expect(first, last, '-'); + if(!neg) + expect(first, last, '+'); T result{}; - if( expect( first, last, "nan" ) ) { - result = std::numeric_limits< T >::quiet_NaN(); - } else if( expect( first, last, "infinity" ) - || expect( first, last, "inf" ) ) { - result = std::numeric_limits< T >::infinity(); + if(expect(first, last, "nan")) { + result = std::numeric_limits::quiet_NaN(); + } else if(expect(first, last, "infinity") + || expect(first, last, "inf")) { + result = std::numeric_limits::infinity(); } else { // TODO: support for hex floats bool valid = false; - if( first != last ) - valid |= is_digit( *first ); - for( int d{}; first != last && ( d = get_digit( *first ) ) >= 0; ++first ) - result = 10 * result + static_cast< T >( d ); - if( expect( first, last, '.' ) ) { - if( first != last ) - valid |= is_digit( *first ); + if(first != last) + valid |= is_digit(*first); + for(int d{}; first != last && (d = get_digit(*first)) >= 0; ++first) + result = 10 * result + static_cast(d); + if(expect(first, last, '.')) { + if(first != last) + valid |= is_digit(*first); T place = 1; - for( int d{}; first != last && ( d = get_digit( *first ) ) >= 0; ++first ) - result += static_cast< T >( d ) * ( place /= 10 ); + for(int d{}; first != last && (d = get_digit(*first)) >= 0; ++first) + result += static_cast(d) * (place /= 10); } - if( !valid ) + if(!valid) return error_code::conversion_error; - if( expect( first, last, 'e' ) ) { - const bool neg_exp = expect( first, last, '-' ); - if( !neg_exp ) - expect( first, last, '+' ); - if( first == last || !is_digit( *first ) ) + if(expect(first, last, 'e')) { + const bool neg_exp = expect(first, last, '-'); + if(!neg_exp) + expect(first, last, '+'); + if(first == last || !is_digit(*first)) return error_code::conversion_error; int exp{}; - for( int d{}; first != last && ( d = get_digit( *first ) ) >= 0; ++first ) - exp = 10 * exp + static_cast< int >( d ); - if( neg_exp ) + for(int d{}; first != last && (d = get_digit(*first)) >= 0; ++first) + exp = 10 * exp + static_cast(d); + if(neg_exp) exp = -exp; - result *= std::pow( T{ 10 }, exp ); + result *= std::pow(T{ 10 }, exp); } } - for( ; first != last && std::isspace( *first ); ++first ); - if( first != last ) + for(; first != last && std::isspace(*first); ++first); + if(first != last) return error_code::conversion_error; return neg ? -result : result; } - template< typename T > - parsing_report< T > str2flt( std::string const& str ) { - return str2flt< T >( str.begin(), str.end() ); + template + parsing_report str2flt(std::string const& str) { + return str2flt(str.begin(), str.end()); } - template< typename T > - parsing_report< T > str2flt( char const* str ) { - return str2flt< T >( str, str + std::strlen( str ) ); + template + parsing_report str2flt(char const* str) { + return str2flt(str, str + std::strlen(str)); } - template< typename T > - std::string int2str( T const& value ) { - static_assert( std::numeric_limits< T >::is_specialized && std::numeric_limits< T >::is_integer, "int2str only supports integral types" ); + template + std::string int2str(T const& value) { + static_assert(std::numeric_limits::is_specialized && std::numeric_limits::is_integer, "int2str only supports integral types"); - return std::to_string( value ); + return std::to_string(value); } - template< typename T > - std::string flt2str( T const& value ) { - static_assert( std::numeric_limits< T >::is_specialized && !std::numeric_limits< T >::is_integer, "flt2str only supports floating point types" ); + template + std::string flt2str(T const& value) { + static_assert(std::numeric_limits::is_specialized && !std::numeric_limits::is_integer, "flt2str only supports floating point types"); // TODO: provide a more efficient implementation std::ostringstream ostrs; @@ -741,11 +741,11 @@ namespace po { }; value() = default; - explicit value( string_t const& object ) + explicit value(string_t const& object) : string{ object } { } - explicit value( string_t&& object ) - : string{ std::move( object ) } { + explicit value(string_t&& object) + : string{ std::move(object) } { } }; @@ -756,33 +756,33 @@ namespace po { virtual value const* begin() const = 0; value* begin() { - return const_cast< value* >( static_cast< value_vector_base const& >( *this ).begin() ); + return const_cast(static_cast(*this).begin()); } value const* end() const { return begin() + size(); } value* end() { - return const_cast< value* >( static_cast< value_vector_base const& >( *this ).end() ); + return const_cast(static_cast(*this).end()); } value const& get() const { - PROGRAMOPTIONS_ASSERT( begin() != nullptr, "value_vector_base: cannot access elements of a void_ vector" ); - PROGRAMOPTIONS_ASSERT( size() != 0, "value_vector_base: cannot access elements of an empty vector" ); - return begin()[ size() - 1 ]; + PROGRAMOPTIONS_ASSERT(begin() != nullptr, "value_vector_base: cannot access elements of a void_ vector"); + PROGRAMOPTIONS_ASSERT(size() != 0, "value_vector_base: cannot access elements of an empty vector"); + return begin()[size() - 1]; } value& get() { - return const_cast< value& >( static_cast< value_vector_base const& >( *this ).get() ); + return const_cast(static_cast(*this).get()); } - virtual void push_back( value const& object ) = 0; + virtual void push_back(value const& object) = 0; }; - template< bool is_void, bool is_single > + template class value_vector; template<> - class value_vector< false, false > final : public value_vector_base { - std::vector< value > m_values; + class value_vector final : public value_vector_base { + std::vector m_values; public: virtual std::size_t size() const override { @@ -791,12 +791,12 @@ namespace po { virtual value const* begin() const override { return &*m_values.begin(); } - virtual void push_back( value const& object ) override { - m_values.push_back( object ); + virtual void push_back(value const& object) override { + m_values.push_back(object); } }; template<> - class value_vector< false, true > final : public value_vector_base { + class value_vector final : public value_vector_base { bool m_set = false; value m_value; @@ -807,13 +807,13 @@ namespace po { virtual value const* begin() const override { return &m_value; } - virtual void push_back( value const& object ) override { + virtual void push_back(value const& object) override { m_value = object; m_set = true; } }; template<> - class value_vector< true, false > final : public value_vector_base { + class value_vector final : public value_vector_base { std::size_t m_counter = 0; public: @@ -823,12 +823,12 @@ namespace po { virtual value const* begin() const override { return nullptr; } - virtual void push_back( value const& /* object */ ) override { // -Wunused-parameter + virtual void push_back(value const& /* object */) override { // -Wunused-parameter ++m_counter; } }; template<> - class value_vector< true, true > final : public value_vector_base { + class value_vector final : public value_vector_base { bool m_set = false; public: @@ -838,30 +838,30 @@ namespace po { virtual value const* begin() const override { return nullptr; } - virtual void push_back( value const& /* object */ ) override { // -Wunused-parameter + virtual void push_back(value const& /* object */) override { // -Wunused-parameter m_set = true; } }; namespace detail { - template< typename fun_t, typename... args_t > + template class is_invocable_sfinae { - template< typename _fun_t, typename... _args_t > - static std::false_type test( ... ); - template< typename _fun_t, typename... _args_t > - static std::true_type test( decltype( std::declval< _fun_t >()( std::declval< _args_t >()... ) )* ); + template + static std::false_type test(...); + template + static std::true_type test(decltype(std::declval<_fun_t>()(std::declval<_args_t>()...))*); public: - using type = decltype( test< fun_t, args_t... >( 0 ) ); + using type = decltype(test(0)); }; } - template< typename fun_t, typename... args_t > - struct is_invocable : public detail::is_invocable_sfinae< fun_t, args_t... >::type { + template + struct is_invocable : public detail::is_invocable_sfinae::type { }; struct callback_base { virtual ~callback_base() = default; - virtual void invoke( value const& object ) = 0; + virtual void invoke(value const& object) = 0; #ifdef PROGRAMOPTIONS_DEBUG virtual bool good() const { return true; @@ -869,29 +869,29 @@ namespace po { #endif // PROGRAMOPTIONS_DEBUG }; - template< typename invocable_t > + template class callback_storage : public callback_base { protected: - typename std::remove_const< typename std::remove_reference< invocable_t >::type >::type m_invocable; + typename std::remove_const::type>::type m_invocable; public: - template< typename... args_t > - explicit callback_storage( args_t&&... args ) - : m_invocable{ std::forward< args_t >( args )... } { + template + explicit callback_storage(args_t&&... args) + : m_invocable{ std::forward(args)... } { } }; template< value_type type, typename invocable_t, - bool with_void = is_invocable< invocable_t >::value, - bool with_string = is_invocable< invocable_t, string_t >::value, - bool with_type = is_invocable< invocable_t, vt2type< type > >::value + bool with_void = is_invocable::value, + bool with_string = is_invocable::value, + bool with_type = is_invocable>::value > - struct callback : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter - PROGRAMOPTIONS_ASSERT( false, "callback: incompatible parameter type" ); + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter + PROGRAMOPTIONS_ASSERT(false, "callback: incompatible parameter type"); } #ifdef PROGRAMOPTIONS_DEBUG virtual bool good() const override { @@ -899,220 +899,220 @@ namespace po { } #endif // PROGRAMOPTIONS_DEBUG }; - template< typename invocable_t, bool with_string, bool with_type > - struct callback< void_, invocable_t, true, with_string, with_type > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< string, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t, bool with_string > - struct callback< string, invocable_t, true, with_string, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< i32, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.i32 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.i32); } }; - template< typename invocable_t, bool with_void > - struct callback< i32, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< i32, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< i64, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.i64 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.i64); } }; - template< typename invocable_t, bool with_void > - struct callback< i64, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< i64, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< u32, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.u32 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.u32); } }; - template< typename invocable_t, bool with_void > - struct callback< u32, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< u32, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< u64, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.u64 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.u64); } }; - template< typename invocable_t, bool with_void > - struct callback< u64, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< u64, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< f32, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.f32 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.f32); } }; - template< typename invocable_t, bool with_void > - struct callback< f32, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< f32, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< typename invocable_t, bool with_void, bool with_string > - struct callback< f64, invocable_t, with_void, with_string, true > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.f64 ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.f64); } }; - template< typename invocable_t, bool with_void > - struct callback< f64, invocable_t, with_void, true, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& object ) override { - this->m_invocable( object.string ); + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& object) override { + this->m_invocable(object.string); } }; - template< typename invocable_t > - struct callback< f64, invocable_t, true, false, false > : public callback_storage< invocable_t > { - using callback_storage< invocable_t >::callback_storage; - virtual void invoke( value const& /* object */ ) override { // -Wunused-parameter + template + struct callback : public callback_storage { + using callback_storage::callback_storage; + virtual void invoke(value const& /* object */) override { // -Wunused-parameter this->m_invocable(); } }; - template< value_type type, typename underlying_t > + template class value_iterator { - static_assert( type != void_, "iterating over voids disallowed" ); - static_assert( std::is_same< typename std::iterator_traits< underlying_t >::iterator_category, std::random_access_iterator_tag >::value, "underlying iterator incompatible" ); + static_assert(type != void_, "iterating over voids disallowed"); + static_assert(std::is_same::iterator_category, std::random_access_iterator_tag>::value, "underlying iterator incompatible"); underlying_t m_underlying; public: - using difference_type = typename std::iterator_traits< underlying_t >::difference_type; - using value_type = vt2type< type >; + using difference_type = typename std::iterator_traits::difference_type; + using value_type = vt2type; using pointer = value_type const*; using reference = value_type const&; using iterator_category = std::random_access_iterator_tag; private: - reference deref( std::integral_constant< ::po::value_type, string > ) const { + reference deref(std::integral_constant<::po::value_type, string>) const { return m_underlying->string; } - reference deref( std::integral_constant< ::po::value_type, i32 > ) const { + reference deref(std::integral_constant<::po::value_type, i32>) const { return m_underlying->i32; } - reference deref( std::integral_constant< ::po::value_type, i64 > ) const { + reference deref(std::integral_constant<::po::value_type, i64>) const { return m_underlying->i64; } - reference deref( std::integral_constant< ::po::value_type, u32 > ) const { + reference deref(std::integral_constant<::po::value_type, u32>) const { return m_underlying->u32; } - reference deref( std::integral_constant< ::po::value_type, u64 > ) const { + reference deref(std::integral_constant<::po::value_type, u64>) const { return m_underlying->u64; } - reference deref( std::integral_constant< ::po::value_type, f32 > ) const { + reference deref(std::integral_constant<::po::value_type, f32>) const { return m_underlying->f32; } - reference deref( std::integral_constant< ::po::value_type, f64 > ) const { + reference deref(std::integral_constant<::po::value_type, f64>) const { return m_underlying->f64; } public: value_iterator() { } - explicit value_iterator( underlying_t const& underlying ) + explicit value_iterator(underlying_t const& underlying) : m_underlying{ underlying } { } reference operator*() const { - return deref( std::integral_constant< ::po::value_type, type >{} ); + return deref(std::integral_constant<::po::value_type, type>{}); } pointer operator->() const { return &operator*(); } - bool operator==( value_iterator const& rhs ) const { + bool operator==(value_iterator const& rhs) const { return m_underlying == rhs.m_underlying; } - bool operator!=( value_iterator const& rhs ) const { + bool operator!=(value_iterator const& rhs) const { return m_underlying != rhs.m_underlying; } - bool operator<( value_iterator const& rhs ) const { + bool operator<(value_iterator const& rhs) const { return m_underlying < rhs.m_underlying; } - bool operator<=( value_iterator const& rhs ) const { + bool operator<=(value_iterator const& rhs) const { return m_underlying <= rhs.m_underlying; } - bool operator>( value_iterator const& rhs ) const { + bool operator>(value_iterator const& rhs) const { return m_underlying > rhs.m_underlying; } - bool operator>=( value_iterator const& rhs ) const { + bool operator>=(value_iterator const& rhs) const { return m_underlying >= rhs.m_underlying; } @@ -1120,7 +1120,7 @@ namespace po { ++m_underlying; return *this; } - value_iterator operator++( int ) { + value_iterator operator++(int) { value_iterator result{ *this }; ++*this; return result; @@ -1129,78 +1129,78 @@ namespace po { --m_underlying; return *this; } - value_iterator operator--( int ) { + value_iterator operator--(int) { value_iterator result{ *this }; --*this; return result; } - value_iterator& operator+=( difference_type n ) { + value_iterator& operator+=(difference_type n) { m_underlying += n; return *this; } - value_iterator& operator-=( difference_type n ) { + value_iterator& operator-=(difference_type n) { m_underlying -= n; return *this; } - difference_type operator-( value_iterator const& rhs ) const { + difference_type operator-(value_iterator const& rhs) const { return m_underlying - rhs.m_underlying; } - reference operator[]( difference_type n ) const { - return *( *this + n ); + reference operator[](difference_type n) const { + return *(*this + n); } }; - template< value_type type, typename underlying_t > - value_iterator< type, underlying_t > operator+( value_iterator< type, underlying_t > object, typename value_iterator< type, underlying_t >::difference_type n ) { + template + value_iterator operator+(value_iterator object, typename value_iterator::difference_type n) { return object += n; } - template< value_type type, typename underlying_t > - value_iterator< type, underlying_t > operator+( typename value_iterator< type, underlying_t >::difference_type n, value_iterator< type, underlying_t > object ) { + template + value_iterator operator+(typename value_iterator::difference_type n, value_iterator object) { return object += n; } - template< value_type type, typename underlying_t > - value_iterator< type, underlying_t > operator-( value_iterator< type, underlying_t > object, typename value_iterator< type, underlying_t >::difference_type n ) { + template + value_iterator operator-(value_iterator object, typename value_iterator::difference_type n) { return object -= n; } namespace detail { - template< typename container_t, typename... args_t > + template class has_push_back_sfinae { - template< typename _container_t, typename... _args_t > - static std::false_type test( ... ); - template< typename _container_t, typename... _args_t > - static std::true_type test( decltype( std::declval< _container_t >().push_back( std::declval< _args_t >()... ) )* ); + template + static std::false_type test(...); + template + static std::true_type test(decltype(std::declval<_container_t>().push_back(std::declval<_args_t>()...))*); public: - using type = decltype( test< container_t, args_t... >( 0 ) ); + using type = decltype(test(0)); }; } - template< typename container_t, typename... args_t > - struct has_push_back : public detail::has_push_back_sfinae< container_t, args_t... >::type { + template + struct has_push_back : public detail::has_push_back_sfinae::type { }; - template< typename container_t > - using has_push_back_vt = has_push_back< container_t, typename container_t::value_type >; + template + using has_push_back_vt = has_push_back; namespace detail { - template< typename container_t, typename... args_t > + template class has_push_sfinae { - template< typename _container_t, typename... _args_t > - static std::false_type test( ... ); - template< typename _container_t, typename... _args_t > - static std::true_type test( decltype( std::declval< _container_t >().push( std::declval< _args_t >()... ) )* ); + template + static std::false_type test(...); + template + static std::true_type test(decltype(std::declval<_container_t>().push(std::declval<_args_t>()...))*); public: - using type = decltype( test< container_t, args_t... >( 0 ) ); + using type = decltype(test(0)); }; } - template< typename container_t, typename... args_t > - struct has_push : public detail::has_push_sfinae< container_t, args_t... >::type { + template + struct has_push : public detail::has_push_sfinae::type { }; - template< typename container_t > - using has_push_vt = has_push< container_t, typename container_t::value_type >; + template + using has_push_vt = has_push; class option { char m_abbreviation = '\0'; @@ -1208,10 +1208,10 @@ namespace po { value_type m_type = void_; bool m_multi = false; - std::unique_ptr< value_vector_base > m_fallback; - std::unique_ptr< value_vector_base > m_data; + std::unique_ptr m_fallback; + std::unique_ptr m_data; - std::vector< std::unique_ptr< callback_base > > m_callbacks; + std::vector> m_callbacks; #ifdef PROGRAMOPTIONS_DEBUG bool m_mutable = true; @@ -1223,7 +1223,7 @@ namespace po { private: void mutable_operation() const { - PROGRAMOPTIONS_ASSERT( m_mutable, "cannot change options after parsing" ); + PROGRAMOPTIONS_ASSERT(m_mutable, "cannot change options after parsing"); } #else // PROGRAMOPTIONS_DEBUG public: @@ -1236,69 +1236,69 @@ namespace po { #endif // PROGRAMOPTIONS_DEBUG value_vector_base const& get_vector() const { - PROGRAMOPTIONS_ASSERT( available(), "cannot access an option with neither user set value nor fallback" ); - if( m_data != nullptr ) + PROGRAMOPTIONS_ASSERT(available(), "cannot access an option with neither user set value nor fallback"); + if(m_data != nullptr) return *m_data; else return *m_fallback; } value_vector_base& get_vector() { - return const_cast< value_vector_base& >( static_cast< option const& >( *this ).get_vector() ); + return const_cast(static_cast