From 3c3894389721d339e70c9996ab528e8795d3f723 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Sun, 8 Apr 2018 14:25:40 +0200
Subject: [PATCH] git subrepo pull packages/CLI11

subrepo:
  subdir:   "packages/CLI11"
  merged:   "4f6bbba3"
upstream:
  origin:   "git@github.com:CLIUtils/CLI11.git"
  branch:   "master"
  commit:   "4f6bbba3"
git-subrepo:
  version:  "0.3.1"
  origin:   "git@github.com:ingydotnet/git-subrepo.git"
  commit:   "a7ee886"
---
 packages/CLI11/.appveyor.yml               |  11 +-
 packages/CLI11/.ci/build_cmake.sh          |  17 ---
 packages/CLI11/.ci/build_doxygen.sh        |   5 +
 packages/CLI11/.ci/build_lcov.sh           |   4 +
 packages/CLI11/.ci/check_tidy.sh           |  16 ++-
 packages/CLI11/.ci/make_and_test.sh        |  20 +++
 packages/CLI11/.ci/prepare_altern.sh       |  18 ---
 packages/CLI11/.ci/run_codecov.sh          |  17 ++-
 packages/CLI11/.ci/travis.sh               |  20 ---
 packages/CLI11/.gitrepo                    |   4 +-
 packages/CLI11/.travis.yml                 | 115 +++++++++--------
 packages/CLI11/CHANGELOG.md                |  30 +++++
 packages/CLI11/CMakeLists.txt              |  40 +++---
 packages/CLI11/README.md                   |  17 ++-
 packages/CLI11/cmake/AddGoogletest.cmake   |  54 +++++---
 packages/CLI11/conanfile.py                |   4 +-
 packages/CLI11/docs/Doxyfile               |   2 +-
 packages/CLI11/examples/CMakeLists.txt     |   2 +-
 packages/CLI11/examples/enum.cpp           |  14 ++-
 packages/CLI11/include/CLI/App.hpp         |  43 ++++---
 packages/CLI11/include/CLI/CLI.hpp         |   4 +
 packages/CLI11/include/CLI/Error.hpp       |   5 +-
 packages/CLI11/include/CLI/Macros.hpp      |  44 +++++++
 packages/CLI11/include/CLI/Option.hpp      | 118 +++++++++++++-----
 packages/CLI11/include/CLI/Optional.hpp    |  78 ++++++++++++
 packages/CLI11/include/CLI/TypeTools.hpp   |  10 +-
 packages/CLI11/scripts/MakeSingleHeader.py | 114 ++++++++++++-----
 packages/CLI11/tests/AppTest.cpp           | 136 ++++++++++++++++-----
 packages/CLI11/tests/CMakeLists.txt        |  46 +++++--
 packages/CLI11/tests/CreationTest.cpp      |  21 +++-
 packages/CLI11/tests/HelpTest.cpp          |  13 +-
 packages/CLI11/tests/HelpersTest.cpp       |   4 +-
 packages/CLI11/tests/NewParseTest.cpp      |  24 ++--
 packages/CLI11/tests/OptionalTest.cpp      |  31 +++++
 packages/CLI11/tests/SimpleTest.cpp        |   2 +-
 packages/CLI11/tests/app_helper.hpp        |   2 +-
 packages/CLI11/tests/informational.cpp     |  50 ++++++++
 37 files changed, 843 insertions(+), 312 deletions(-)
 delete mode 100644 packages/CLI11/.ci/build_cmake.sh
 create mode 100755 packages/CLI11/.ci/make_and_test.sh
 delete mode 100644 packages/CLI11/.ci/prepare_altern.sh
 delete mode 100755 packages/CLI11/.ci/travis.sh
 create mode 100644 packages/CLI11/include/CLI/Macros.hpp
 create mode 100644 packages/CLI11/include/CLI/Optional.hpp
 create mode 100644 packages/CLI11/tests/OptionalTest.cpp
 create mode 100644 packages/CLI11/tests/informational.cpp

diff --git a/packages/CLI11/.appveyor.yml b/packages/CLI11/.appveyor.yml
index 6d4f5b5e6..91a95a011 100644
--- a/packages/CLI11/.appveyor.yml
+++ b/packages/CLI11/.appveyor.yml
@@ -1,6 +1,6 @@
 branches:
-  except:
-    - gh-pages
+  only:
+    - master
 
 install:
   - set PATH=C:\Python36;%PATH%
@@ -12,13 +12,14 @@ install:
 build_script:
   - mkdir build
   - cd build
-  - cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_GENERATOR="Visual Studio 14 2015"
-  - cmake --build .
+  - ps: cmake .. -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_GENERATOR="Visual Studio 14 2015"
+  - ps: cmake --build .
   - cd ..
   - conan create . CLIUtils/CLI11
 
 test_script:
-  - ctest --output-on-failure -C Debug
+  - cd build
+  - ps: ctest --output-on-failure -C Debug
 
 notifications:
   - provider: Webhook
diff --git a/packages/CLI11/.ci/build_cmake.sh b/packages/CLI11/.ci/build_cmake.sh
deleted file mode 100644
index 5b2d69bb6..000000000
--- a/packages/CLI11/.ci/build_cmake.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-CMAKE_VERSION=3.9.6
-CMAKE_MVERSION=${CMAKE_VERSION%.*}
-# Non Bash version:
-# echo CMAKE_MVERSION=`$var | awk -F"." '{ print $1"."$2 }'`
-
-if [ "$TRAVIS_OS_NAME" = "linux" ] ; then CMAKE_URL="https://cmake.org/files/v${CMAKE_MVERSION}/cmake-${CMAKE_VERSION}-Linux-x86_64.tar.gz" ; fi
-if [ "$TRAVIS_OS_NAME" = "osx" ] ; then CMAKE_URL="https://cmake.org/files/v$CMAKE_MVERSION/cmake-$CMAKE_VERSION-Darwin-x86_64.tar.gz" ; fi
-cd "${DEPS_DIR}"
-
-if [[ ! -f "${DEPS_DIR}/cmake/bin/cmake" ]] ; then
-  echo "Downloading CMake $CMAKE_VERSION"
-  mkdir -p cmake
-  travis_retry wget --no-check-certificate --quiet -O - "${CMAKE_URL}" | tar --strip-components=1 -xz -C cmake
-fi
-
-export PATH="${DEPS_DIR}/cmake/bin:${PATH}"
-cd "${TRAVIS_BUILD_DIR}"
diff --git a/packages/CLI11/.ci/build_doxygen.sh b/packages/CLI11/.ci/build_doxygen.sh
index 5087f2be1..6772ecf97 100644
--- a/packages/CLI11/.ci/build_doxygen.sh
+++ b/packages/CLI11/.ci/build_doxygen.sh
@@ -1,3 +1,5 @@
+set -evx
+
 DOXYGEN_URL="ftp://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.13.src.tar.gz"
 cd "${DEPS_DIR}"
 
@@ -15,3 +17,6 @@ fi
 export PATH="${DEPS_DIR}/doxygen/build/bin:${PATH}"
 
 cd "${TRAVIS_BUILD_DIR}"
+
+set +evx
+
diff --git a/packages/CLI11/.ci/build_lcov.sh b/packages/CLI11/.ci/build_lcov.sh
index 3b89dd33c..8671d7881 100644
--- a/packages/CLI11/.ci/build_lcov.sh
+++ b/packages/CLI11/.ci/build_lcov.sh
@@ -1,3 +1,5 @@
+set -evx
+
 LCOV_URL="http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.13.orig.tar.gz"
 cd "${DEPS_DIR}"
 
@@ -9,3 +11,5 @@ fi
 
 export PATH="${DEPS_DIR}/lcov/bin:${PATH}"
 cd "${TRAVIS_BUILD_DIR}"
+
+set +evx
diff --git a/packages/CLI11/.ci/check_tidy.sh b/packages/CLI11/.ci/check_tidy.sh
index 55189d9e4..505b68eb9 100755
--- a/packages/CLI11/.ci/check_tidy.sh
+++ b/packages/CLI11/.ci/check_tidy.sh
@@ -1,11 +1,21 @@
-#!/usr/bin/env sh
+#!/usr/bin/env bash
+
+echo -en "travis_fold:start:script.build\\r"
+echo "Building with tidy on..."
 set -evx
 
-mkdir build-tidy || true
+mkdir -p build-tidy
 cd build-tidy
-CXX_FLAGS="-Werror -Wall -Wextra -pedantic -std=c++11" cmake .. -DCLANG_TIDY_FIX=ON
+CXX_FLAGS="-Werror -Wcast-align -Wfloat-equal -Wimplicit-atomic-properties -Wmissing-declarations -Woverlength-strings -Wshadow -Wstrict-selector-match -Wundeclared-selector -Wunreachable-code -std=c++11" cmake .. -DCLANG_TIDY_FIX=ON
 cmake --build .
 
+set -evx
+echo -en "travis_fold:end:script.build\\r"
+echo -en "travis_fold:start:script.compare\\r"
+echo "Checking git diff..."
+set -evx
+
 git diff --exit-code --color
 
 set +evx
+echo -en "travis_fold:end:script.compare\\r"
diff --git a/packages/CLI11/.ci/make_and_test.sh b/packages/CLI11/.ci/make_and_test.sh
new file mode 100755
index 000000000..2ba81aeef
--- /dev/null
+++ b/packages/CLI11/.ci/make_and_test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+echo -en "travis_fold:start:script.build\\r"
+echo "Building..."
+set -evx
+
+mkdir -p build
+cd build
+cmake .. -DCLI11_CXX_STD=$1 -DCLI11_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
+cmake --build . -- -j2
+
+set +evx
+echo -en "travis_fold:end:script.build\\r"
+echo -en "travis_fold:start:script.test\\r"
+echo "Testing..."
+set -evx
+
+ctest --output-on-failure
+
+set +evx
+echo -en "travis_fold:end:script.test\\r"
diff --git a/packages/CLI11/.ci/prepare_altern.sh b/packages/CLI11/.ci/prepare_altern.sh
deleted file mode 100644
index e384b0034..000000000
--- a/packages/CLI11/.ci/prepare_altern.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-cd "${DEPS_DIR}"
-mkdir -p extrabin
-cd extrabin
-
-if [ "$CXX" = "g++" ] ; then
-    ln -s `which gcc-$COMPILER` gcc
-    ln -s `which g++-$COMPILER` g++
-    ln -s `which gcov-$COMPILER` gcov
-else
-    ln -s `which clang-$COMPILER` clang
-    ln -s `which clang++-$COMPILER` clang++
-    ln -s `which clang-format-$COMPILER` clang-format
-    ln -s `which clang-tidy-$COMPILER` clang-tidy
-fi
-
-export PATH="${DEPS_DIR}/extrabin":$PATH
-
-cd "${TRAVIS_BUILD_DIR}"
diff --git a/packages/CLI11/.ci/run_codecov.sh b/packages/CLI11/.ci/run_codecov.sh
index cd7219a8c..28d149a53 100755
--- a/packages/CLI11/.ci/run_codecov.sh
+++ b/packages/CLI11/.ci/run_codecov.sh
@@ -1,14 +1,27 @@
+#!/usr/bin/env bash
+
+echo -en "travis_fold:start:script.build\\r"
+echo "Building..."
 set -evx
 
 cd ${TRAVIS_BUILD_DIR}
 mkdir -p build
 cd build
-cmake .. -DCLI_SINGLE_FILE_TESTS=OFF -DCLI_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Coverage
+cmake .. -DCLI11_SINGLE_FILE_TESTS=OFF -DCLI11_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Coverage
 cmake --build . -- -j2
-cmake --build . --target CLI_coverage
+cmake --build . --target CLI11_coverage
+
+set +evx
+echo -en "travis_fold:end:script.build\\r"
+echo -en "travis_fold:start:script.lcov\\r"
+echo "Capturing and uploading LCov..."
+set -evx
 
 lcov --directory . --capture --output-file coverage.info # capture coverage info
 lcov --remove coverage.info '*/tests/*' '*/examples/*' '*gtest*' '*gmock*' '/usr/*' --output-file coverage.info # filter out system
 lcov --list coverage.info #debug info
 # Uploading report to CodeCov
 bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"
+
+set +evx
+echo -en "travis_fold:end:script.lcov\\r"
diff --git a/packages/CLI11/.ci/travis.sh b/packages/CLI11/.ci/travis.sh
deleted file mode 100755
index 49cc2f8ea..000000000
--- a/packages/CLI11/.ci/travis.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env sh
-set -evx
-
-mkdir build || true
-cd build
-cmake .. -DCLI_CXX_STD=11 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
-cmake --build . -- -j2
-ctest --output-on-failure
-if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "14" ] ; then
-    cmake .. -DCLI_CXX_STD=14 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
-    cmake --build . -- -j2
-    ctest --output-on-failure
-fi
-if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "17" ] ; then
-    cmake .. -DCLI_CXX_STD=17 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug
-    cmake --build . -- -j2
-    ctest --output-on-failure
-fi
-
-set +evx
diff --git a/packages/CLI11/.gitrepo b/packages/CLI11/.gitrepo
index 11c78bd36..8e84b44c4 100644
--- a/packages/CLI11/.gitrepo
+++ b/packages/CLI11/.gitrepo
@@ -6,6 +6,6 @@
 [subrepo]
 	remote = git@github.com:CLIUtils/CLI11.git
 	branch = master
-	commit = b4b7d991f69add2e4fb007d1df4c14a088127d9b
-	parent = 8546076c470f8af8014418e169819302cd7d1f66
+	commit = 4f6bbba3170dc9b1f0c671298e12d8b49c160ce0
+	parent = 4326875f2ca41888cc0384b68d2a90324b7580cc
 	cmdver = 0.3.1
diff --git a/packages/CLI11/.travis.yml b/packages/CLI11/.travis.yml
index c02c44b06..872aa39f9 100644
--- a/packages/CLI11/.travis.yml
+++ b/packages/CLI11/.travis.yml
@@ -1,82 +1,98 @@
 language: cpp
 sudo: false
 dist: trusty
+
+# Exclude ghpages,
+# but even better, don't build branch and PR, just PR
 branches:
-  exclude:
-  - gh-pages
+  only:
+  - master
+
 cache:
+  ccache: true
+  apt: true
   directories:
-  - "${TRAVIS_BUILD_DIR}/deps/cmake"
   - "${TRAVIS_BUILD_DIR}/deps/doxygen"
+
 matrix:
   include:
+    # Default clang
   - compiler: clang
-    addons:
-      apt:
-        sources:
-        - ubuntu-toolchain-r-test
-        - llvm-toolchain-trusty-5.0
-        packages:
-        - clang++-5.0
-    env:
-    - COMPILER=5.0
-    - CLI_CXX_STD=14
-  - compiler: clang
-    addons:
-      apt:
-        packages:
-        - clang-3.9
-        - clang-format-3.9
-        - clang-tidy-3.9
+    script:
+    - .ci/make_and_test.sh 11
+    - .ci/make_and_test.sh 14
+    - .ci/make_and_test.sh 17
+
+    # Check style/tidy
+  - compiler: clang 
     env:
-    - COMPILER=3.9
-    - CLI_CXX_STD=14
+    - CHECK_STYLE=yes
     script:
     - cd "${TRAVIS_BUILD_DIR}"
     - scripts/check_style.sh
-    - ".ci/check_tidy.sh"
+    - .ci/check_tidy.sh
+
+    # Docs and clang 3.5
   - compiler: clang
+    env:
+    - DEPLOYMAT=yes
     addons:
       apt:
         packages:
         - clang-3.5
-    env:
-    - COMPILER=3.5
-    - DEPLOY_MAT=yes
-    - DOXYFILE=$TRAVIS_BUILD_DIR/docs/Doxyfile
+    install:
+    - export CC=clang-3.5
+    - export CXX=clang++-3.5
+    script:
+    - .ci/make_and_test.sh 11
     after_success:
+    - export DOXYFILE=$TRAVIS_BUILD_DIR/docs/Doxyfile
     - |
       if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]
       then
-        echo "Updating docs" && cd $TRAVIS_BUILD_DIR && .ci/build_docs.sh
+        . .ci/build_doxygen.sh
+        .ci/build_docs.sh
       fi
+
+    # GCC 6 and Coverage
   - compiler: gcc
+    env:
+    - GCC_VER=7
     addons:
       apt:
         sources:
         - ubuntu-toolchain-r-test
         packages:
-        - g++-6
+        - g++-7
         - curl
         - lcov
-    env:
-    - COMPILER=6
-    - CLI_CXX_STD=14
-    before_install:
+    install:
+    - export CC=gcc-7
+    - export CXX=g++-7
     - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
     - cd $TRAVIS_BUILD_DIR
     - ". .ci/build_lcov.sh"
     - ".ci/run_codecov.sh"
+    script:
+    - .ci/make_and_test.sh 11
+    - .ci/make_and_test.sh 14
+    - .ci/make_and_test.sh 17
+
+    # GCC 4.7 and Conan
   - compiler: gcc
+    env:
+    - GCC_VER=4.7
     addons:
       apt:
         packages:
         - g++-4.7
-    env:
-    - COMPILER=4.7
-    before_install:
+    install:
+    - export CC=gcc-4.7
+    - export CXX=g++-4.7
     - python -m pip install --user conan
     - conan user
+    script:
+    - .ci/make_and_test.sh 11
     after_success:
     - conan create . CLIUtils/stable
     - |
@@ -86,33 +102,28 @@ matrix:
         conan user -p ${BINFROG_API_KEY} -r origin henryiii
         conan upload "*" -c -r origin --all
       fi
+
+    # macOS and clang
   - os: osx
     compiler: clang
-    before_install:
+    install:
     - brew update
     - echo 'brew "python"' > Brewfile
     - echo 'brew "conan"' >> Brewfile
+    - echo 'brew "ccache"' >> Brewfile
     - brew bundle
     - python -m ensurepip --user
     - conan user
     after_success:
     - conan create . CLIUtils/CLI11
-install:
-- python -c 'import sys; print(sys.version_info[:])'
-- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
-- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd $TRAVIS_BUILD_DIR && . .ci/prepare_altern.sh
-  ; fi
-- if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_cmake.sh
-  ; fi
-- if [ "$TRAVIS_OS_NAME" = "linux" ] ; then cd $TRAVIS_BUILD_DIR && . .ci/build_doxygen.sh
-  ; fi
-- cd "${DEPS_DIR}"
-- if [ "$(python -c 'import sys; print(sys.version_info[0])')" = "2" ] ; then python
-  -m pip install --user pathlib ; fi
-- cmake --version
+
+install: skip
+
 script:
-- cd "${TRAVIS_BUILD_DIR}"
-- ".ci/travis.sh"
+- .ci/make_and_test.sh 11
+- .ci/make_and_test.sh 14
+
+
 deploy:
   provider: releases
   api_key:
diff --git a/packages/CLI11/CHANGELOG.md b/packages/CLI11/CHANGELOG.md
index 279ebe327..f1f52fe82 100644
--- a/packages/CLI11/CHANGELOG.md
+++ b/packages/CLI11/CHANGELOG.md
@@ -1,3 +1,33 @@
+## In progress
+
+This version has some internal cleanup and improved support for the newest compilers.
+
+Note: This is the final release with `requires`, please switch to `needs`.
+
+* Fix unlimited short options eating two values before checking for positionals when no space present [#90]
+* Symmetric exclude text when excluding options, exclude can be called multiple times [#64]
+* Support for `std::optional`, `std::experimental::optional`, and `boost::optional` added if `__has_include` is supported [#95]
+* All macros/CMake variables now start with `CLI11_` instead of just `CLI_` [#95]
+* The internal stream was not being cleared before use in some cases. Fixed. [#95]
+* Using an emum now requires explicit conversion overload [#97]
+
+Other, non-user facing changes:
+
+* Added `Macros.hpp` with better C++ mode discovery [#95]
+* Deprecated macros added for all platforms
+* C++17 is now tested on supported platforms [#95]
+* Informational printout now added to CTest [#95]
+* Better single file generation [#95]
+* Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next version of GTest)
+* Types now have a specific size, separate from the expected number - cleaner and more powerful internally [#92]
+
+[#64]: https://github.com/CLIUtils/CLI11/issues/64
+[#90]: https://github.com/CLIUtils/CLI11/issues/90
+[#92]: https://github.com/CLIUtils/CLI11/issues/92
+[#95]: https://github.com/CLIUtils/CLI11/pull/95
+[#97]: https://github.com/CLIUtils/CLI11/pull/97
+
+
 ## Version 1.4: More feedback
 
 This version adds lots of smaller fixes and additions after the refactor in version 1.3. More ways to download and use CLI11 in CMake have been added. INI files have improved support.
diff --git a/packages/CLI11/CMakeLists.txt b/packages/CLI11/CMakeLists.txt
index f31547e3b..040ae0e00 100644
--- a/packages/CLI11/CMakeLists.txt
+++ b/packages/CLI11/CMakeLists.txt
@@ -16,10 +16,10 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
 # Only if built as the main project
 if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
     # User settable
-    set(CLI_CXX_STD "11"  CACHE STRING "The CMake standard to require")
+    set(CLI11_CXX_STD "11"  CACHE STRING "The CMake standard to require")
 
     set(CUR_PROJ ON)
-    set(CMAKE_CXX_STANDARD ${CLI_CXX_STD})
+    set(CMAKE_CXX_STANDARD ${CLI11_CXX_STD})
     set(CMAKE_CXX_EXTENSIONS OFF)
     set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
@@ -27,7 +27,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
     if(MSVC)
         add_definitions("/W4")
     else()
-        add_definitions("-Wall -Wextra -pedantic")
+        add_definitions(-Wall -Wextra -pedantic -Wno-deprecated-declarations)
     endif()
 
     if(CMAKE_VERSION VERSION_GREATER 3.6)
@@ -51,15 +51,18 @@ else()
     set(CUR_PROJ OFF)
 endif()
 
+# Allow dependent options
+include(CMakeDependentOption)
+
 # Allow IDE's to group targets into folders
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
 if(CMAKE_BUILD_TYPE STREQUAL Coverage)
     include(CodeCoverage)
-    setup_target_for_coverage(CLI_coverage ctest coverage)
+    setup_target_for_coverage(CLI11_coverage ctest coverage)
 endif()
 
-file(GLOB CLI_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*")
+file(GLOB CLI11_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/*")
 # To see in IDE, must be listed for target
 
 add_library(CLI11 INTERFACE)
@@ -112,19 +115,14 @@ export(PACKAGE CLI11)
 
 # Single file test
 find_package(PythonInterp)
-if(CUR_PROJ AND PYTHONINTERP_FOUND)
-    set(CLI_SINGLE_FILE_DEFAULT ON)
-else()
-    set(CLI_SINGLE_FILE_DEFAULT OFF)
-endif()
+cmake_dependent_option(CLI11_SINGLE_FILE "Generate a single header file" ON "CUR_PROJ;PYTHONINTERP_FOUND" OFF)
 
-option(CLI_SINGLE_FILE "Generate a single header file" ${CLI_SINGLE_FILE_DEFAULT})
-if(CLI_SINGLE_FILE)
+if(CLI11_SINGLE_FILE)
     find_package(PythonInterp REQUIRED)
     file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include")
     add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
         COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/MakeSingleHeader.py" "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp"
-        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI_headers}
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/CLI.hpp" ${CLI11_headers}
         )
     add_custom_target(generate_cli_single_file ALL
         DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/CLI11.hpp")
@@ -134,27 +132,23 @@ if(CLI_SINGLE_FILE)
     add_library(CLI11_SINGLE INTERFACE)
     target_link_libraries(CLI11_SINGLE INTERFACE CLI11)
     add_dependencies(CLI11_SINGLE generate_cli_single_file)
-    target_compile_definitions(CLI11_SINGLE INTERFACE -DCLI_SINGLE_FILE)
+    target_compile_definitions(CLI11_SINGLE INTERFACE -DCLI11_SINGLE_FILE)
     target_include_directories(CLI11_SINGLE INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include/")
 endif()
 
-option(CLI_SINGLE_FILE_TESTS "Duplicate all the tests for a single file build" OFF)
+option(CLI11_SINGLE_FILE_TESTS "Duplicate all the tests for a single file build" OFF)
 
-option(CLI_TESTING "Build the tests and add them" ${CUR_PROJ})
-if(CLI_TESTING)
+cmake_dependent_option(CLI11_TESTING "Build the tests and add them" ON "CUR_PROJ" OFF)
+if(CLI11_TESTING)
     enable_testing()
     add_subdirectory(tests)
 endif()
 
-option(CLI_EXAMPLES "Build the examples" ${CUR_PROJ})
-if(CLI_EXAMPLES)
+cmake_dependent_option(CLI11_EXAMPLES "Build the examples" ON "CUR_PROJ" OFF)
+if(CLI11_EXAMPLES)
     add_subdirectory(examples)
 endif()
 
-if(NOT CUR_PROJ)
-    mark_as_advanced(CLI_SINGLE_FILE_TESTS CLI_EXAMPLES CLI_TESTING)
-endif()
-
 # Packaging support
 set(CPACK_PACKAGE_VENDOR "github.com/CLIUtils/CLI11")
 set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Command line interface")
diff --git a/packages/CLI11/README.md b/packages/CLI11/README.md
index f2c2cf0a1..437208ae9 100644
--- a/packages/CLI11/README.md
+++ b/packages/CLI11/README.md
@@ -63,7 +63,7 @@ After I wrote this, I also found the following libraries:
 | [Argh!] | Very minimalistic C++11 parser, single header. Don't have many features. No help generation?!?! At least it's exception-free.|
 | [CLI]   | Custom language and parser. Huge build-system overkill for very little benefit. Last release in 2009, but still occasionally active. |
 
-See [Awesome C++] for a less-biased list of parsers.
+See [Awesome C++] for a less-biased list of parsers. You can also find other single file libraries at [Single file libs].
 
 </p></details>
 <br/>
@@ -164,6 +164,8 @@ An option name must start with a alphabetic character or underscore. For long op
 
 On a C++14 compiler, you can pass a callback function directly to `.add_flag`, while in C++11 mode you'll need to use `.add_flag_function` if you want a callback function. The function will be given the number of times the flag was passed. You can throw a relevant `CLI::ParseError` to signal a failure.
 
+On a compiler that supports C++17's `__has_include`, you can also use `std::optional`, `std::experimental::optional`, and `boost::optional` directly in an `add_option` call. If you don't have `__has_include`, you can define `CLI11_BOOST_OPTIONAL` before including CLI11 to manually add support for `boost::optional`. See [CLI11 Internals] for information on how this was done and how you can add your own converters.
+
 ### Example
 
 * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--one`
@@ -305,7 +307,11 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent
 ## How it works
 
 Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
-`false` if it failed. If you wanted to extend this to support a new type, just use a lambda. An example of a new parser for `complex<double>` that supports all of the features of a standard `add_options` call is in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
+`false` if it failed.
+
+Other values can be added as long as they support `operator>>` (and defaults can be printed if they support `operator<<`). To add an enum, for example, provide a custom `operator>>` with an `istream` (inside the CLI namespace is fine if you don't want to interfere with an existing `operator>>`).
+
+If you wanted to extend this to support a completely new type, just use a lambda. An example of a new parser for `complex<double>` that supports all of the features of a standard `add_options` call is in [one of the tests](./tests/NewParseTest.cpp). A simpler example is shown below:
 
 ### Example
 
@@ -421,6 +427,7 @@ CLI11 was developed at the [University of Cincinnati] to support of the [GooFit]
 [NSF Award 1414736]:     https://nsf.gov/awardsearch/showAward?AWD_ID=1414736
 [University of Cincinnati]: http://www.uc.edu
 [GitBook]:               https://cliutils.gitlab.io/CLI11Tutorial
+[CLI11 Internals]:       https://cliutils.gitlab.io/CLI11Tutorial/chapters/internals.html
 [ProgramOptions.hxx]:    https://github.com/Fytch/ProgramOptions.hxx
 [Argument Aggregator]:   https://github.com/vietjtnguyen/argagg
 [Args]:                  https://github.com/Taywee/args
@@ -434,5 +441,7 @@ CLI11 was developed at the [University of Cincinnati] to support of the [GooFit]
 [wandbox-link]:          https://wandbox.org/permlink/g7tRkuU8xY3aTIVP
 [releases-badge]:        https://img.shields.io/github/release/CLIUtils/CLI11.svg
 [cli11-po-compare]:      https://iscinumpy.gitlab.io/post/comparing-cli11-and-boostpo/
-[DIANA slides]: https://indico.cern.ch/event/619465/contributions/2507949/attachments/1448567/2232649/20170424-diana-2.pdf
-[Awesome C++]: https://github.com/fffaraz/awesome-cpp/blob/master/README.md#cli
+[DIANA slides]:          https://indico.cern.ch/event/619465/contributions/2507949/attachments/1448567/2232649/20170424-diana-2.pdf
+[Awesome C++]:           https://github.com/fffaraz/awesome-cpp/blob/master/README.md#cli
+[CLI]:                   https://codesynthesis.com/projects/cli/
+[Single file libs]:      https://github.com/nothings/single_file_libs/blob/master/README.md
diff --git a/packages/CLI11/cmake/AddGoogletest.cmake b/packages/CLI11/cmake/AddGoogletest.cmake
index 80eb9ed6e..e6bf162ae 100644
--- a/packages/CLI11/cmake/AddGoogletest.cmake
+++ b/packages/CLI11/cmake/AddGoogletest.cmake
@@ -4,24 +4,38 @@
 # gives output on failed tests without having to set an environment variable.
 #
 #
-set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+set(BUILD_SHARED_LIBS OFF)
 
-include(DownloadProject)
-download_project(PROJ                googletest
-                 GIT_REPOSITORY      https://github.com/google/googletest.git
-                 GIT_TAG             release-1.8.0
-                 UPDATE_DISCONNECTED 1
-                 QUIET
-)
+if(CMAKE_VERSION VERSION_LESS 3.11)
+    set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
+    include(DownloadProject)
+    download_project(PROJ                googletest
+                     GIT_REPOSITORY      https://github.com/google/googletest.git
+                     GIT_TAG             release-1.8.0
+                     UPDATE_DISCONNECTED 1
+                     QUIET
+    )
+    
+    # CMake warning suppression will not be needed in version 1.9
+    set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "")
+    add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL)
+else()
+    include(FetchContent)
+    FetchContent_Declare(googletest
+        GIT_REPOSITORY      https://github.com/google/googletest.git
+        GIT_TAG             release-1.8.0)
+    FetchContent_GetProperties(googletest)
+    if(NOT googletest_POPULATED)
+        FetchContent_Populate(googletest)
+        set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "")
+        add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL)
+    endif()
+endif()
 
-set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
 
-# CMake warning suppression will not be needed in version 1.9
-set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "")
-add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL)
-unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS)
 
-if (CMAKE_CONFIGURATION_TYPES)
+if(CMAKE_CONFIGURATION_TYPES)
     add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} 
         --force-new-ctest-process --output-on-failure 
         --build-config "$<CONFIGURATION>")
@@ -54,16 +68,17 @@ macro(add_gtest TESTNAME)
             gtest_add_tests(TARGET ${TESTNAME}
                             TEST_PREFIX "${TESTNAME}."
                             TEST_LIST TmpTestList)
+            set_tests_properties(${TmpTestList} PROPERTIES FOLDER "Tests")
         else()
             gtest_discover_tests(${TESTNAME}
                 TEST_PREFIX "${TESTNAME}."
-                )
+                PROPERTIES FOLDER "Tests")
             
         endif()
     else()
         add_test(${TESTNAME} ${TESTNAME})
+        set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests")
     endif()
-    set_target_properties(${TESTNAME} PROPERTIES FOLDER "Tests")
 
 endmacro()
 
@@ -80,3 +95,10 @@ BUILD_GTEST
 
 set_target_properties(gtest gtest_main gmock gmock_main
     PROPERTIES FOLDER "Extern")
+
+if(MSVC AND MSVC_VERSION GREATER_EQUAL 1900)
+    target_compile_definitions(gtest PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
+    target_compile_definitions(gtest_main PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
+    target_compile_definitions(gmock PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
+    target_compile_definitions(gmock_main PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
+endif()
diff --git a/packages/CLI11/conanfile.py b/packages/CLI11/conanfile.py
index 77e584f9a..7a32f711d 100644
--- a/packages/CLI11/conanfile.py
+++ b/packages/CLI11/conanfile.py
@@ -22,8 +22,8 @@ class HelloConan(ConanFile):
 
     def build(self): # this is not building a library, just tests
         cmake = CMake(self)
-        cmake.definitions["CLI_EXAMPLES"] = "OFF"
-        cmake.definitions["CLI_SINGLE_FILE"] = "OFF"
+        cmake.definitions["CLI11_EXAMPLES"] = "OFF"
+        cmake.definitions["CLI11_SINGLE_FILE"] = "OFF"
         cmake.configure()
         cmake.build()
         cmake.test()
diff --git a/packages/CLI11/docs/Doxyfile b/packages/CLI11/docs/Doxyfile
index 5363a26e1..0e2a8c75b 100644
--- a/packages/CLI11/docs/Doxyfile
+++ b/packages/CLI11/docs/Doxyfile
@@ -334,7 +334,7 @@ BUILTIN_STL_SUPPORT    = NO
 # enable parsing support.
 # The default value is: NO.
 
-CPP_CLI_SUPPORT        = NO
+CPP_CLI11_SUPPORT        = NO
 
 # Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
 # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
diff --git a/packages/CLI11/examples/CMakeLists.txt b/packages/CLI11/examples/CMakeLists.txt
index c2eef50cc..8c2f13b3c 100644
--- a/packages/CLI11/examples/CMakeLists.txt
+++ b/packages/CLI11/examples/CMakeLists.txt
@@ -1,5 +1,5 @@
 function(add_cli_exe T)
-    add_executable(${T} ${ARGN} ${CLI_headers})
+    add_executable(${T} ${ARGN} ${CLI11_headers})
     target_link_libraries(${T} PUBLIC CLI11)
     set_target_properties(
          ${T} PROPERTIES
diff --git a/packages/CLI11/examples/enum.cpp b/packages/CLI11/examples/enum.cpp
index 827bee392..7018681fa 100644
--- a/packages/CLI11/examples/enum.cpp
+++ b/packages/CLI11/examples/enum.cpp
@@ -1,12 +1,22 @@
+#include <sstream>
 #include <CLI/CLI.hpp>
 
-enum Level : std::int32_t { High, Medium, Low };
+enum class Level : int { High, Medium, Low };
+
+std::istream &operator>>(std::istream &in, Level &level) {
+    int i;
+    in >> i;
+    level = static_cast<Level>(i);
+    return in;
+}
+
+std::ostream &operator<<(std::ostream &in, const Level &level) { return in << static_cast<int>(level); }
 
 int main(int argc, char **argv) {
     CLI::App app;
 
     Level level;
-    app.add_set("-l,--level", level, {High, Medium, Low}, "Level settings")
+    app.add_set("-l,--level", level, {Level::High, Level::Medium, Level::Low}, "Level settings")
         ->set_type_name("enum/Level in {High=0, Medium=1, Low=2}");
 
     CLI11_PARSE(app, argc, argv);
diff --git a/packages/CLI11/include/CLI/App.hpp b/packages/CLI11/include/CLI/App.hpp
index 8fd85e470..543b85a19 100644
--- a/packages/CLI11/include/CLI/App.hpp
+++ b/packages/CLI11/include/CLI/App.hpp
@@ -19,6 +19,7 @@
 // CLI Library includes
 #include "CLI/Error.hpp"
 #include "CLI/Ini.hpp"
+#include "CLI/Macros.hpp"
 #include "CLI/Option.hpp"
 #include "CLI/Split.hpp"
 #include "CLI/StringTools.hpp"
@@ -196,6 +197,9 @@ class App {
         set_help_flag("-h,--help", "Print this help message and exit");
     }
 
+    /// virtual destructor
+    virtual ~App() = default;
+
     /// Set a callback for the end of parsing.
     ///
     /// Due to a bug in c++11,
@@ -447,7 +451,7 @@ class App {
         return opt;
     }
 
-#if __cplusplus >= 201402L
+#ifdef CLI11_CPP14
     /// Add option for callback (C++14 or better only)
     Option *add_flag(std::string name,
                      std::function<void(size_t)> function, ///< A function to call, void(size_t)
@@ -834,7 +838,7 @@ class App {
                 std::string value;
 
                 // Non-flags
-                if(opt->get_expected() != 0) {
+                if(opt->get_type_size() != 0) {
 
                     // If the option was found on command line
                     if(opt->count() > 0)
@@ -1048,10 +1052,10 @@ class App {
 
     /// This returns the number of remaining options, minus the -- seperator
     size_t remaining_size(bool recurse = false) const {
-        size_t count = std::count_if(
+        size_t count = static_cast<size_t>(std::count_if(
             std::begin(missing_), std::end(missing_), [](const std::pair<detail::Classifer, std::string> &val) {
                 return val.first != detail::Classifer::POSITIONAL_MARK;
-            });
+            }));
         if(recurse) {
             for(const App_p &sub : subcommands_) {
                 count += sub->remaining_size(recurse);
@@ -1068,7 +1072,7 @@ class App {
     /// Currently checks to see if multiple positionals exist with -1 args
     void _validate() const {
         auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
-            return opt->get_expected() == -1 && opt->get_positional();
+            return opt->get_items_expected() < 0 && opt->get_positional();
         });
         if(count > 1)
             throw InvalidError(name_);
@@ -1188,8 +1192,8 @@ class App {
             // Required or partially filled
             if(opt->get_required() || opt->count() != 0) {
                 // Make sure enough -N arguments parsed (+N is already handled in parsing function)
-                if(opt->get_expected() < 0 && opt->count() < static_cast<size_t>(-opt->get_expected()))
-                    throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_expected());
+                if(opt->get_items_expected() < 0 && opt->count() < static_cast<size_t>(-opt->get_items_expected()))
+                    throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_items_expected());
 
                 // Required but empty
                 if(opt->get_required() && opt->count() == 0)
@@ -1259,7 +1263,7 @@ class App {
 
         if(op->results_.empty()) {
             // Flag parsing
-            if(op->get_expected() == 0) {
+            if(op->get_type_size() == 0) {
                 if(current.inputs.size() == 1) {
                     std::string val = current.inputs.at(0);
                     val = detail::to_lower(val);
@@ -1319,9 +1323,9 @@ class App {
     size_t _count_remaining_positionals(bool required = false) const {
         size_t retval = 0;
         for(const Option_p &opt : options_)
-            if(opt->get_positional() && (!required || opt->get_required()) && opt->get_expected() > 0 &&
-               static_cast<int>(opt->count()) < opt->get_expected())
-                retval = static_cast<size_t>(opt->get_expected()) - opt->count();
+            if(opt->get_positional() && (!required || opt->get_required()) && opt->get_items_expected() > 0 &&
+               static_cast<int>(opt->count()) < opt->get_items_expected())
+                retval = static_cast<size_t>(opt->get_items_expected()) - opt->count();
 
         return retval;
     }
@@ -1333,7 +1337,7 @@ class App {
         for(const Option_p &opt : options_) {
             // Eat options, one by one, until done
             if(opt->get_positional() &&
-               (static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) {
+               (static_cast<int>(opt->count()) < opt->get_items_expected() || opt->get_items_expected() < 0)) {
 
                 opt->add_result(positional);
                 parse_order_.push_back(opt.get());
@@ -1420,27 +1424,34 @@ class App {
         // Get a reference to the pointer to make syntax bearable
         Option_p &op = *op_ptr;
 
-        int num = op->get_expected();
+        int num = op->get_items_expected();
 
+        // Make sure we always eat the minimum for unlimited vectors
+        int collected = 0;
+
+        // --this=value
         if(!value.empty()) {
-            if(num != -1)
+            // If exact number expected
+            if(num > 0)
                 num--;
             op->add_result(value);
             parse_order_.push_back(op.get());
+            collected += 1;
         } else if(num == 0) {
             op->add_result("");
             parse_order_.push_back(op.get());
+            // -Trest
         } else if(!rest.empty()) {
             if(num > 0)
                 num--;
             op->add_result(rest);
             parse_order_.push_back(op.get());
             rest = "";
+            collected += 1;
         }
 
         // Unlimited vector parser
         if(num < 0) {
-            int collected = 0; // Make sure we always eat the minimum
             while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
                 if(collected >= -num) {
                     // We could break here for allow extras, but we don't
@@ -1451,7 +1462,7 @@ class App {
 
                     // If there are any unlimited positionals, those also take priority
                     if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) {
-                           return opt->get_positional() && opt->get_expected() < 0;
+                           return opt->get_positional() && opt->get_items_expected() < 0;
                        }))
                         break;
                 }
diff --git a/packages/CLI11/include/CLI/CLI.hpp b/packages/CLI11/include/CLI/CLI.hpp
index 53a0cef23..662e833dd 100644
--- a/packages/CLI11/include/CLI/CLI.hpp
+++ b/packages/CLI11/include/CLI/CLI.hpp
@@ -8,6 +8,10 @@
 
 #include "CLI/Version.hpp"
 
+#include "CLI/Macros.hpp"
+
+#include "CLI/Optional.hpp"
+
 #include "CLI/StringTools.hpp"
 
 #include "CLI/Error.hpp"
diff --git a/packages/CLI11/include/CLI/Error.hpp b/packages/CLI11/include/CLI/Error.hpp
index bd47806b0..09104a651 100644
--- a/packages/CLI11/include/CLI/Error.hpp
+++ b/packages/CLI11/include/CLI/Error.hpp
@@ -91,6 +91,9 @@ class IncorrectConstruction : public ConstructionError {
     static IncorrectConstruction Set0Opt(std::string name) {
         return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
     }
+    static IncorrectConstruction SetFlag(std::string name) {
+        return IncorrectConstruction(name + ": Cannot set an expected number for flags");
+    }
     static IncorrectConstruction ChangeNotVector(std::string name) {
         return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
     }
@@ -102,7 +105,7 @@ class IncorrectConstruction : public ConstructionError {
         return IncorrectConstruction("Option " + name + " is not defined");
     }
     static IncorrectConstruction MultiOptionPolicy(std::string name) {
-        return IncorrectConstruction(name + ": multi_option_policy only works for flags and single value options");
+        return IncorrectConstruction(name + ": multi_option_policy only works for flags and exact value options");
     }
 };
 
diff --git a/packages/CLI11/include/CLI/Macros.hpp b/packages/CLI11/include/CLI/Macros.hpp
new file mode 100644
index 000000000..9c10b0814
--- /dev/null
+++ b/packages/CLI11/include/CLI/Macros.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+// Distributed under the 3-Clause BSD License.  See accompanying
+// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
+
+namespace CLI {
+
+// Note that all code in CLI11 must be in a namespace, even if it just a define.
+
+// The following version macro is very similar to the one in PyBind11
+
+#if !(defined(_MSC_VER) && __cplusplus == 199711L) && !defined(__INTEL_COMPILER)
+#if __cplusplus >= 201402L
+#define CLI11_CPP14
+#if __cplusplus >= 201703L
+#define CLI11_CPP17
+#if __cplusplus > 201703L
+#define CLI11_CPP20
+#endif
+#endif
+#endif
+#elif defined(_MSC_VER) && __cplusplus == 199711L
+// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully implemented)
+// Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3 or newer
+#if _MSVC_LANG >= 201402L
+#define CLI11_CPP14
+#if _MSVC_LANG > 201402L && _MSC_VER >= 1910
+#define CLI11_CPP17
+#if __MSVC_LANG > 201703L && _MSC_VER >= 1910
+#define CLI11_CPP20
+#endif
+#endif
+#endif
+#endif
+
+#if defined(PYBIND11_CPP14)
+#define CLI11_DEPRECATED(reason) [[deprecated(reason)]]
+#elif defined(_MSC_VER)
+#define CLI11_DEPRECATED(reason) __declspec(deprecated(reason))
+#else
+#define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason)))
+#endif
+
+} // namespace CLI
diff --git a/packages/CLI11/include/CLI/Option.hpp b/packages/CLI11/include/CLI/Option.hpp
index f8222d349..dd61dfd9d 100644
--- a/packages/CLI11/include/CLI/Option.hpp
+++ b/packages/CLI11/include/CLI/Option.hpp
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "CLI/Error.hpp"
+#include "CLI/Macros.hpp"
 #include "CLI/Split.hpp"
 #include "CLI/StringTools.hpp"
 
@@ -179,11 +180,13 @@ class Option : public OptionBase<Option> {
     /// @name Configuration
     ///@{
 
-    /// The number of expected values, 0 for flag, -1 for unlimited vector
-    int expected_{1};
+    /// The number of arguments that make up one option. -1=unlimited (vector-like), 0=flag, 1=normal option,
+    /// 2=complex/pair, etc. Set only when the option is created; this is intrinsic to the type. Eventually, -2 may mean
+    /// vector of pairs.
+    int type_size_{1};
 
-    /// A private setting to allow args to not be able to accept incorrect expected values
-    bool changeable_{false};
+    /// The number of expected values, type_size_ must be < 0. Ignored for flag. N < 0 means at least -N values.
+    int expected_{1};
 
     /// A list of validators to run on each value parsed
     std::vector<std::function<std::string(std::string &)>> validators_;
@@ -243,14 +246,25 @@ class Option : public OptionBase<Option> {
     /// @name Setting options
     ///@{
 
-    /// Set the number of expected arguments (Flags bypass this)
+    /// Set the number of expected arguments (Flags don't use this)
     Option *expected(int value) {
-        if(expected_ == value)
-            return this;
+        // Break if this is a flag
+        if(type_size_ == 0)
+            throw IncorrectConstruction::SetFlag(single_name());
+
+        // Setting 0 is not allowed
         else if(value == 0)
             throw IncorrectConstruction::Set0Opt(single_name());
-        else if(!changeable_)
+
+        // No change is okay, quit now
+        else if(expected_ == value)
+            return this;
+
+        // Type must be a vector
+        else if(type_size_ >= 0)
             throw IncorrectConstruction::ChangeNotVector(single_name());
+
+        // TODO: Can support multioption for non-1 values (except for join)
         else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
             throw IncorrectConstruction::AfterMultiOpt(single_name());
 
@@ -299,25 +313,36 @@ class Option : public OptionBase<Option> {
         return needs(opt1, args...);
     }
 
-#if __cplusplus <= 201703L
+#ifndef CLI11_CPP20
     /// Sets required options \deprecated
+    CLI11_DEPRECATED("Use needs instead of requires (eventual keyword clash)")
     Option *requires(Option *opt) { return needs(opt); }
 
     /// Can find a string if needed \deprecated
-    template <typename T = App> Option *requires(std::string opt_name) { return needs<T>(opt_name); }
+    template <typename T = App> Option *requires(std::string opt_name) {
+        for(const Option_p &opt : dynamic_cast<T *>(parent_)->options_)
+            if(opt.get() != this && opt->check_name(opt_name))
+                return needs(opt.get());
+        throw IncorrectConstruction::MissingOption(opt_name);
+    }
 
     /// Any number supported, any mix of string and Opt \deprecated
     template <typename A, typename B, typename... ARG> Option *requires(A opt, B opt1, ARG... args) {
-        needs(opt);
-        return needs(opt1, args...);
+        requires(opt);
+        return requires(opt1, args...);
     }
 #endif
 
     /// Sets excluded options
     Option *excludes(Option *opt) {
-        auto tup = excludes_.insert(opt);
-        if(!tup.second)
-            throw OptionAlreadyAdded::Excludes(get_name(), opt->get_name());
+        excludes_.insert(opt);
+
+        // Help text should be symmetric - excluding a should exclude b
+        opt->excludes_.insert(this);
+
+        // Ignoring the insert return value, excluding twice is now allowed.
+        // (Mostly to allow both directions to be excluded by user, even though the library does it for you.)
+
         return this;
     }
 
@@ -356,9 +381,10 @@ class Option : public OptionBase<Option> {
         return this;
     }
 
-    /// Take the last argument if given multiple times
+    /// Take the last argument if given multiple times (or another policy)
     Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
-        if(get_expected() != 0 && get_expected() != 1)
+
+        if(get_items_expected() < 0)
             throw IncorrectConstruction::MultiOptionPolicy(single_name());
         multi_option_policy_ = value;
         return this;
@@ -369,8 +395,32 @@ class Option : public OptionBase<Option> {
     ///@{
 
     /// The number of arguments the option expects
+    int get_type_size() const { return type_size_; }
+
+    /// The number of times the option expects to be included
     int get_expected() const { return expected_; }
 
+    /// \breif The total number of expected values (including the type)
+    /// This is positive if exactly this number is expected, and negitive for at least N values
+    ///
+    /// v = fabs(size_type*expected)
+    /// !MultiOptionPolicy::Throw
+    ///           | Expected < 0  | Expected == 0 | Expected > 0
+    /// Size < 0  |      -v       |       0       |     -v
+    /// Size == 0 |       0       |       0       |      0
+    /// Size > 0  |      -v       |       0       |     -v       // Expected must be 1
+    ///
+    /// MultiOptionPolicy::Throw
+    ///           | Expected < 0  | Expected == 0 | Expected > 0
+    /// Size < 0  |      -v       |       0       |      v
+    /// Size == 0 |       0       |       0       |      0
+    /// Size > 0  |       v       |       0       |      v      // Expected must be 1
+    ///
+    int get_items_expected() const {
+        return std::abs(type_size_ * expected_) *
+               ((multi_option_policy_ != MultiOptionPolicy::Throw || (expected_ < 0 && type_size_ < 0) ? -1 : 1));
+    }
+
     /// True if this has a default value
     int get_default() const { return default_; }
 
@@ -416,7 +466,7 @@ class Option : public OptionBase<Option> {
         return out;
     }
 
-    /// The most discriptive name available
+    /// The most descriptive name available
     std::string single_name() const {
         if(!lnames_.empty())
             return std::string("--") + lnames_[0];
@@ -444,7 +494,7 @@ class Option : public OptionBase<Option> {
     std::string help_aftername() const {
         std::stringstream out;
 
-        if(get_expected() != 0) {
+        if(get_type_size() != 0) {
             if(!typeval_.empty())
                 out << " " << typeval_;
             if(!defaultval_.empty())
@@ -488,20 +538,29 @@ class Option : public OptionBase<Option> {
 
         bool local_result;
 
+        // Num items expected or length of vector, always at least 1
+        // Only valid for a trimming policy
+        int trim_size = std::min(std::max(std::abs(get_items_expected()), 1), static_cast<int>(results_.size()));
+
         // Operation depends on the policy setting
         if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
-            results_t partial_result = {results_.back()};
+            // Allow multi-option sizes (including 0)
+            results_t partial_result{results_.end() - trim_size, results_.end()};
             local_result = !callback_(partial_result);
+
         } else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
-            results_t partial_result = {results_.at(0)};
+            results_t partial_result{results_.begin(), results_.begin() + trim_size};
             local_result = !callback_(partial_result);
+
         } else if(multi_option_policy_ == MultiOptionPolicy::Join) {
             results_t partial_result = {detail::join(results_, "\n")};
             local_result = !callback_(partial_result);
+
         } else {
-            if((expected_ > 0 && results_.size() != static_cast<size_t>(expected_)) ||
-               (expected_ < 0 && results_.size() < static_cast<size_t>(-expected_)))
-                throw ArgumentMismatch(single_name(), expected_, results_.size());
+            // For now, vector of non size 1 types are not supported but possibility included here
+            if((get_items_expected() > 0 && results_.size() != static_cast<size_t>(get_items_expected())) ||
+               (get_items_expected() < 0 && results_.size() < static_cast<size_t>(-get_items_expected())))
+                throw ArgumentMismatch(single_name(), get_items_expected(), results_.size());
             else
                 local_result = !callback_(results_);
         }
@@ -583,13 +642,14 @@ class Option : public OptionBase<Option> {
     /// @name Custom options
     ///@{
 
-    /// Set a custom option, typestring, expected; locks changeable unless expected is -1
-    void set_custom_option(std::string typeval, int expected = 1) {
+    /// Set a custom option, typestring, type_size
+    void set_custom_option(std::string typeval, int type_size = 1) {
         typeval_ = typeval;
-        expected_ = expected;
-        if(expected == 0)
+        type_size_ = type_size;
+        if(type_size_ == 0)
             required_ = false;
-        changeable_ = expected < 0;
+        if(type_size < 0)
+            expected_ = -1;
     }
 
     /// Set the default value string representation
diff --git a/packages/CLI11/include/CLI/Optional.hpp b/packages/CLI11/include/CLI/Optional.hpp
new file mode 100644
index 000000000..1597da336
--- /dev/null
+++ b/packages/CLI11/include/CLI/Optional.hpp
@@ -0,0 +1,78 @@
+#pragma once
+
+// Distributed under the 3-Clause BSD License.  See accompanying
+// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
+
+#include <istream>
+
+#include "CLI/Macros.hpp"
+
+// [CLI11:verbatim]
+#ifdef __has_include
+#if defined(CLI11_CPP17) && __has_include(<optional>)
+#include <optional>
+#ifdef __cpp_lib_optional
+#ifndef CLI11_STD_OPTIONAL
+#define CLI11_STD_OPTIONAL
+#endif
+#endif
+#endif
+#if defined(CLI11_CPP14) && __has_include(<experimental/optional>)
+#include <experimental/optional>
+#ifndef CLI11_EXPERIMENTAL_OPTIONAL
+#define CLI11_EXPERIMENTAL_OPTIONAL
+#endif
+#endif
+#if __has_include(<boost/optional.hpp>)
+#include <boost/optional.hpp>
+#ifndef CLI11_BOOST_OPTIONAL
+#define CLI11_BOOST_OPTIONAL
+#endif
+#endif
+#endif
+// [CLI11:verbatim]
+
+namespace CLI {
+
+#ifdef CLI11_STD_OPTIONAL
+template <typename T> std::istream &operator>>(std::istream &in, std::optional<T> &val) {
+    T v;
+    in >> v;
+    val = v;
+    return in;
+}
+#endif
+
+#ifdef CLI11_EXPERIMENTAL_OPTIONAL
+template <typename T> std::istream &operator>>(std::istream &in, std::experimental::optional<T> &val) {
+    T v;
+    in >> v;
+    val = v;
+    return in;
+}
+#endif
+
+#ifdef CLI11_BOOST_OPTIONAL
+template <typename T> std::istream &operator>>(std::istream &in, boost::optional<T> &val) {
+    T v;
+    in >> v;
+    val = v;
+    return in;
+}
+#endif
+
+// Export the best optional to the CLI namespace
+#if defined(CLI11_STD_OPTIONAL)
+using std::optional;
+#elif defined(CLI11_EXPERIMENTAL_OPTIONAL)
+using std::experimental::optional;
+#elif defined(CLI11_BOOST_OPTIONAL)
+using boost::optional;
+#endif
+
+// This is true if any optional is found
+#if defined(CLI11_STD_OPTIONAL) || defined(CLI11_EXPERIMENTAL_OPTIONAL) || defined(CLI11_BOOST_OPTIONAL)
+#define CLI11_OPTIONAL
+#endif
+
+} // namespace CLI
diff --git a/packages/CLI11/include/CLI/TypeTools.hpp b/packages/CLI11/include/CLI/TypeTools.hpp
index fecdbafd2..aea4b8568 100644
--- a/packages/CLI11/include/CLI/TypeTools.hpp
+++ b/packages/CLI11/include/CLI/TypeTools.hpp
@@ -74,8 +74,7 @@ constexpr const char *type_name() {
 
 /// Signed integers / enums
 template <typename T,
-          enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value) || std::is_enum<T>::value,
-                      detail::enabler> = detail::dummy>
+          enable_if_t<(std::is_integral<T>::value && std::is_signed<T>::value), detail::enabler> = detail::dummy>
 bool lexical_cast(std::string input, T &output) {
     try {
         size_t n = 0;
@@ -124,7 +123,7 @@ bool lexical_cast(std::string input, T &output) {
 
 /// String and similar
 template <typename T,
-          enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
+          enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
                           std::is_assignable<T &, std::string>::value,
                       detail::enabler> = detail::dummy>
 bool lexical_cast(std::string input, T &output) {
@@ -134,17 +133,18 @@ bool lexical_cast(std::string input, T &output) {
 
 /// Non-string parsable
 template <typename T,
-          enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value &&
+          enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value &&
                           !std::is_assignable<T &, std::string>::value,
                       detail::enabler> = detail::dummy>
 bool lexical_cast(std::string input, T &output) {
 
 // On GCC 4.7, thread_local is not available, so this optimization
-// is turned off (avoiding multiple initialisations on multiple usages
+// is turned off (avoiding multiple initialisations on multiple usages)
 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && __GNUC__ == 4 && (__GNUC_MINOR__ < 8)
     std::istringstream is;
 #else
     static thread_local std::istringstream is;
+    is.clear();
 #endif
 
     is.str(input);
diff --git a/packages/CLI11/scripts/MakeSingleHeader.py b/packages/CLI11/scripts/MakeSingleHeader.py
index e6985beb1..d260ab959 100755
--- a/packages/CLI11/scripts/MakeSingleHeader.py
+++ b/packages/CLI11/scripts/MakeSingleHeader.py
@@ -1,66 +1,114 @@
 #!/usr/bin/env python
 
-# Requires pathlib on python 2
-
 from __future__ import print_function, unicode_literals
 
 import os
 import re
 import argparse
+import operator
+from copy import copy
 from subprocess import check_output, CalledProcessError
+from functools import reduce
 
 includes_local = re.compile(r"""^#include "(.*)"$""", re.MULTILINE)
 includes_system = re.compile(r"""^#include \<(.*)\>$""", re.MULTILINE)
+verbatim_tag_str = r"""
+^               # Begin of line
+[^\n^\[]+       # Some characters, not including [ or the end of a line
+\[              # A literal [
+[^\]^\n]*       # Anything except a closing ]
+CLI11:verbatim  # The tag
+[^\]^\n]*       # Anything except a closing ]
+\]              # A literal ]
+[^\n]*          # Up to end of line
+$               # End of a line
+"""
+verbatim_all = re.compile(verbatim_tag_str + "(.*)" + verbatim_tag_str,
+                          re.MULTILINE | re.DOTALL | re.VERBOSE)
+
+DIR = os.path.dirname(os.path.abspath(__file__))
+
+class HeaderFile(object):
+    TAG = "Unknown git revision"
+
+    def __init__(self, base, inc):
+        with open(os.path.join(base, inc)) as f:
+            inner = f.read()
 
-DIR = os.path.dirname(os.path.abspath(__file__)) # Path(__file__).resolve().parent
-BDIR = os.path.join(os.path.dirname(DIR), 'include') # DIR.parent / 'include'
+        # add self.verbatim
+        if 'CLI11:verbatim' in inner:
+            self.verbatim = ["\n\n// Verbatim copy from {}".format(inc)]
+            self.verbatim += verbatim_all.findall(inner)
+            inner = verbatim_all.sub("", inner)
+        else:
+            self.verbatim = []
 
-print("Git directory:", DIR)
+        self.headers = set(includes_system.findall(inner))
 
-try:
-    TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8")
-except CalledProcessError:
-    TAG = "A non-git source"
+        self.body = '\n// From {}\n\n'.format(inc) + inner[inner.find('namespace'):]
 
-def MakeHeader(out):
-    main_header = os.path.join(BDIR, 'CLI', 'CLI.hpp')
-    with open(main_header) as f:
-        header = f.read()
+    def __add__(self, other):
+        out = copy(self)
+        out.headers |= other.headers
+        out.body += other.body
+        out.verbatim += other.verbatim
+        return out
 
-    include_files = includes_local.findall(header)
+    @property
+    def header_str(self):
+        return '\n'.join('#include <'+h+'>' for h in sorted(self.headers))
 
-    headers = set()
-    output = ''
-    for inc in include_files:
-        with open(os.path.join(BDIR, inc)) as f:
-            inner = f.read()
-        headers |= set(includes_system.findall(inner))
-        output += '\n// From {inc}\n\n'.format(inc=inc)
-        output += inner[inner.find('namespace'):]
-
-    header_list = '\n'.join('#include <'+h+'>' for h in headers)
+    @property
+    def verbatim_str(self):
+        return '\n'.join(self.verbatim)
 
-    output = '''\
+    def __str__(self):
+        return '''\
 #pragma once
 
 // Distributed under the 3-Clause BSD License.  See accompanying
 // file LICENSE or https://github.com/CLIUtils/CLI11 for details.
 
 // This file was generated using MakeSingleHeader.py in CLI11/scripts
-// from: {tag}
+// from: {self.TAG}
 // This has the complete CLI library in one file.
 
-{header_list}
-{output}'''.format(header_list=header_list, output=output, tag=TAG)
+{self.header_str}
+{self.verbatim_str}
+{self.body}
+'''.format(self=self)
+
+
+def MakeHeader(output, main_header, include_dir = '../include'):
+    # Set tag if possible to class variable
+    try:
+        HeaderFile.TAG = check_output(['git', 'describe', '--tags', '--always'], cwd=str(DIR)).decode("utf-8")
+    except CalledProcessError:
+        pass
 
-    with open(out, 'w') as f:
-        f.write(output)
+    base_dir = os.path.abspath(os.path.join(DIR, include_dir))
+    main_header = os.path.join(base_dir, main_header)
 
-    print("Created {out}".format(out=out))
+    with open(main_header) as f:
+        header = f.read()
+
+    include_files = includes_local.findall(header)
+
+    headers = [HeaderFile(base_dir, inc) for inc in include_files]
+    single_header = reduce(operator.add, headers)
+
+    with open(output, 'w') as f:
+        f.write(str(single_header))
+
+    print("Created", output)
 
 
 if __name__ == '__main__':
     parser = argparse.ArgumentParser()
-    parser.add_argument("output", nargs='?', default=os.path.join(BDIR, 'CLI11.hpp'))
+    parser.add_argument("output", help="Single header file output")
+    parser.add_argument("--main", default='CLI/CLI.hpp', help="The main include file that defines the other files")
+    parser.add_argument("--include", default='../include')
     args = parser.parse_args()
-    MakeHeader(args.output)
+
+    MakeHeader(args.output, args.main, args.include)
+
diff --git a/packages/CLI11/tests/AppTest.cpp b/packages/CLI11/tests/AppTest.cpp
index e53f9a135..0b1c24164 100644
--- a/packages/CLI11/tests/AppTest.cpp
+++ b/packages/CLI11/tests/AppTest.cpp
@@ -1,5 +1,6 @@
 #include "app_helper.hpp"
 #include <cstdlib>
+#include <complex>
 
 TEST_F(TApp, OneFlagShort) {
     app.add_flag("-c,--count");
@@ -290,6 +291,40 @@ TEST_F(TApp, JoinOpt2) {
     EXPECT_EQ(str, "one\ntwo");
 }
 
+TEST_F(TApp, TakeLastOptMulti) {
+    std::vector<int> vals;
+    app.add_option("--long", vals)->expected(2)->take_last();
+
+    args = {"--long", "1", "2", "3"};
+
+    run();
+
+    EXPECT_EQ(vals, std::vector<int>({2, 3}));
+}
+
+TEST_F(TApp, TakeFirstOptMulti) {
+    std::vector<int> vals;
+    app.add_option("--long", vals)->expected(2)->take_first();
+
+    args = {"--long", "1", "2", "3"};
+
+    run();
+
+    EXPECT_EQ(vals, std::vector<int>({1, 2}));
+}
+
+TEST_F(TApp, ComplexOptMulti) {
+    std::complex<double> val;
+    app.add_complex("--long", val)->take_first();
+
+    args = {"--long", "1", "2", "3", "4"};
+
+    run();
+
+    EXPECT_DOUBLE_EQ(val.real(), 1);
+    EXPECT_DOUBLE_EQ(val.imag(), 2);
+}
+
 TEST_F(TApp, MissingValueNonRequiredOpt) {
     int count;
     app.add_option("-c,--count", count);
@@ -318,6 +353,23 @@ TEST_F(TApp, MissingValueMoreThan) {
     EXPECT_THROW(run(), CLI::ArgumentMismatch);
 }
 
+TEST_F(TApp, NoMissingValueMoreThan) {
+    std::vector<int> vals1;
+    std::vector<int> vals2;
+    app.add_option("-v", vals1)->expected(-2);
+    app.add_option("--vals", vals2)->expected(-2);
+
+    args = {"-v", "2", "3", "4"};
+    run();
+    EXPECT_EQ(vals1, std::vector<int>({2, 3, 4}));
+
+    app.reset();
+
+    args = {"--vals", "2", "3", "4"};
+    run();
+    EXPECT_EQ(vals2, std::vector<int>({2, 3, 4}));
+}
+
 TEST_F(TApp, NotRequiredOptsSingle) {
 
     std::string str;
@@ -415,6 +467,52 @@ TEST_F(TApp, RequiredOptsDoubleNeg) {
     EXPECT_EQ(strs, std::vector<std::string>({"one", "two"}));
 }
 
+// This makes sure unlimited option priority is
+// correct for space vs. no space #90
+TEST_F(TApp, PositionalNoSpace) {
+    std::vector<std::string> options;
+    std::string foo, bar;
+
+    app.add_option("-O", options);
+    app.add_option("foo", foo)->required();
+    app.add_option("bar", bar)->required();
+
+    args = {"-O", "Test", "param1", "param2"};
+    run();
+
+    EXPECT_EQ(options.size(), (size_t)1);
+    EXPECT_EQ(options.at(0), "Test");
+
+    app.reset();
+    args = {"-OTest", "param1", "param2"};
+    run();
+
+    EXPECT_EQ(options.size(), (size_t)1);
+    EXPECT_EQ(options.at(0), "Test");
+}
+
+TEST_F(TApp, PositionalNoSpaceLong) {
+    std::vector<std::string> options;
+    std::string foo, bar;
+
+    app.add_option("--option", options);
+    app.add_option("foo", foo)->required();
+    app.add_option("bar", bar)->required();
+
+    args = {"--option", "Test", "param1", "param2"};
+    run();
+
+    EXPECT_EQ(options.size(), (size_t)1);
+    EXPECT_EQ(options.at(0), "Test");
+
+    app.reset();
+    args = {"--option=Test", "param1", "param2"};
+    run();
+
+    EXPECT_EQ(options.size(), (size_t)1);
+    EXPECT_EQ(options.at(0), "Test");
+}
+
 TEST_F(TApp, RequiredOptsUnlimited) {
 
     std::vector<std::string> strs;
@@ -545,26 +643,6 @@ TEST_F(TApp, NotRequiedExpectedDoubleShort) {
     EXPECT_THROW(run(), CLI::ArgumentMismatch);
 }
 
-TEST_F(TApp, EnumTest) {
-    enum Level : std::int32_t { High, Medium, Low };
-    Level level = Level::Low;
-    app.add_option("--level", level);
-
-    args = {"--level", "1"};
-    run();
-    EXPECT_EQ(level, Level::Medium);
-}
-
-TEST_F(TApp, NewEnumTest) {
-    enum class Level2 : std::int32_t { High, Medium, Low };
-    Level2 level = Level2::Low;
-    app.add_option("--level", level);
-
-    args = {"--level", "1"};
-    run();
-    EXPECT_EQ(level, Level2::Medium);
-}
-
 TEST_F(TApp, RequiredFlags) {
     app.add_flag("-a")->required();
     app.add_flag("-b")->mandatory(); // Alternate term
@@ -587,24 +665,24 @@ TEST_F(TApp, RequiredFlags) {
 
 TEST_F(TApp, CallbackFlags) {
 
-    int value = 0;
+    size_t value = 0;
 
     auto func = [&value](size_t x) { value = x; };
 
     app.add_flag_function("-v", func);
 
     run();
-    EXPECT_EQ(value, 0);
+    EXPECT_EQ(value, (size_t)0);
 
     app.reset();
     args = {"-v"};
     run();
-    EXPECT_EQ(value, 1);
+    EXPECT_EQ(value, (size_t)1);
 
     app.reset();
     args = {"-vv"};
     run();
-    EXPECT_EQ(value, 2);
+    EXPECT_EQ(value, (size_t)2);
 
     EXPECT_THROW(app.add_flag_function("hi", func), CLI::IncorrectConstruction);
 }
@@ -612,24 +690,24 @@ TEST_F(TApp, CallbackFlags) {
 #if __cplusplus >= 201402L
 TEST_F(TApp, CallbackFlagsAuto) {
 
-    int value = 0;
+    size_t value = 0;
 
     auto func = [&value](size_t x) { value = x; };
 
     app.add_flag("-v", func);
 
     run();
-    EXPECT_EQ(value, 0);
+    EXPECT_EQ(value, (size_t)0);
 
     app.reset();
     args = {"-v"};
     run();
-    EXPECT_EQ(value, 1);
+    EXPECT_EQ(value, (size_t)1);
 
     app.reset();
     args = {"-vv"};
     run();
-    EXPECT_EQ(value, 2);
+    EXPECT_EQ(value, (size_t)2);
 
     EXPECT_THROW(app.add_flag("hi", func), CLI::IncorrectConstruction);
 }
@@ -1115,7 +1193,7 @@ TEST_F(TApp, NeedsMixedFlags) {
     run();
 }
 
-#if __cplusplus <= 201703L
+#ifndef CLI11_CPP20
 
 TEST_F(TApp, RequiresMixedFlags) {
     CLI::Option *opt1 = app.add_flag("--opt1");
diff --git a/packages/CLI11/tests/CMakeLists.txt b/packages/CLI11/tests/CMakeLists.txt
index e2ae6d2c8..4c191fcc4 100644
--- a/packages/CLI11/tests/CMakeLists.txt
+++ b/packages/CLI11/tests/CMakeLists.txt
@@ -1,7 +1,7 @@
-set(GOOGLE_TEST_INDIVIDUAL ON)
+set(GOOGLE_TEST_INDIVIDUAL OFF)
 include(AddGoogletest)
 
-set(CLI_TESTS
+set(CLI11_TESTS
     HelpersTest
     IniTest
     SimpleTest
@@ -10,22 +10,23 @@ set(CLI_TESTS
     SubcommandTest
     HelpTest
     NewParseTest
+    OptionalTest
     )
 
-set(CLI_MULTIONLY_TESTS
+set(CLI11_MULTIONLY_TESTS
     TimerTest
     )
 
 # Only affects current directory, so safe
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 
-foreach(T ${CLI_TESTS})
+foreach(T ${CLI11_TESTS})
 
-    add_executable(${T} ${T}.cpp ${CLI_headers})
+    add_executable(${T} ${T}.cpp ${CLI11_headers})
     target_link_libraries(${T} PUBLIC CLI11)
     add_gtest(${T})
 
-    if(CLI_SINGLE_FILE AND CLI_SINGLE_FILE_TESTS)
+    if(CLI11_SINGLE_FILE AND CLI11_SINGLE_FILE_TESTS)
         add_executable(${T}_Single ${T}.cpp)
         target_link_libraries(${T}_Single PUBLIC CLI11_SINGLE)
         add_gtest(${T}_Single)
@@ -36,9 +37,9 @@ foreach(T ${CLI_TESTS})
 
 endforeach()
 
-foreach(T ${CLI_MULTIONLY_TESTS})
+foreach(T ${CLI11_MULTIONLY_TESTS})
 
-    add_executable(${T} ${T}.cpp ${CLI_headers})
+    add_executable(${T} ${T}.cpp ${CLI11_headers})
     target_link_libraries(${T} PUBLIC CLI11)
     add_gtest(${T})
 
@@ -52,3 +53,32 @@ set_target_properties(link_test_1 PROPERTIES FOLDER "Tests")
 add_executable(link_test_2 link_test_2.cpp)
 target_link_libraries(link_test_2 PUBLIC CLI11 link_test_1)
 add_gtest(link_test_2)
+
+# Add informational printout
+# Force this to be in a standard location so CTest can find it
+add_executable(informational informational.cpp)
+target_link_libraries(informational PUBLIC CLI11)
+set_target_properties(informational PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}"
+    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}"
+    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}"
+    RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}"
+    RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}"
+    )
+
+# Adding this printout to CTest
+file(WRITE "${PROJECT_BINARY_DIR}/CTestCustom.cmake"
+    "set(CTEST_CUSTOM_PRE_TEST \"${CMAKE_BINARY_DIR}/informational\")"
+    )
+
+# Add boost to test boost::optional if available
+find_package(Boost 1.35)
+if(Boost_FOUND)
+    target_link_libraries(informational PUBLIC Boost::boost)
+    target_link_libraries(OptionalTest PUBLIC Boost::boost)
+
+    # Enforce Boost::Optional even if __has_include is missing on your compiler
+    target_compile_definitions(informational PUBLIC CLI11_BOOST_OPTIONAL)
+    target_compile_definitions(OptionalTest PUBLIC CLI11_BOOST_OPTIONAL)
+endif()
+
diff --git a/packages/CLI11/tests/CreationTest.cpp b/packages/CLI11/tests/CreationTest.cpp
index b95e6c0a1..cee6d3bdd 100644
--- a/packages/CLI11/tests/CreationTest.cpp
+++ b/packages/CLI11/tests/CreationTest.cpp
@@ -125,7 +125,7 @@ TEST_F(TApp, IncorrectConstructionFlagPositional3) {
 
 TEST_F(TApp, IncorrectConstructionFlagExpected) {
     auto cat = app.add_flag("--cat");
-    EXPECT_NO_THROW(cat->expected(0));
+    EXPECT_THROW(cat->expected(0), CLI::IncorrectConstruction);
     EXPECT_THROW(cat->expected(1), CLI::IncorrectConstruction);
 }
 
@@ -168,6 +168,13 @@ TEST_F(TApp, IncorrectConstructionNeedsCannotFind) {
     EXPECT_THROW(cat->needs("--nothing"), CLI::IncorrectConstruction);
 }
 
+#ifndef CLI11_CPP20
+TEST_F(TApp, IncorrectConstructionRequiresCannotFind) {
+    auto cat = app.add_flag("--cat");
+    EXPECT_THROW(cat->requires("--nothing"), CLI::IncorrectConstruction);
+}
+#endif
+
 TEST_F(TApp, IncorrectConstructionExcludesCannotFind) {
     auto cat = app.add_flag("--cat");
     EXPECT_THROW(cat->excludes("--nothing"), CLI::IncorrectConstruction);
@@ -187,18 +194,20 @@ TEST_F(TApp, IncorrectConstructionDuplicateNeedsTxt) {
     EXPECT_THROW(cat->needs("--other"), CLI::OptionAlreadyAdded);
 }
 
-TEST_F(TApp, IncorrectConstructionDuplicateExcludes) {
+// Now allowed
+TEST_F(TApp, CorrectConstructionDuplicateExcludes) {
     auto cat = app.add_flag("--cat");
     auto other = app.add_flag("--other");
     ASSERT_NO_THROW(cat->excludes(other));
-    EXPECT_THROW(cat->excludes(other), CLI::OptionAlreadyAdded);
+    ASSERT_NO_THROW(other->excludes(cat));
 }
 
-TEST_F(TApp, IncorrectConstructionDuplicateExcludesTxt) {
+// Now allowed
+TEST_F(TApp, CorrectConstructionDuplicateExcludesTxt) {
     auto cat = app.add_flag("--cat");
-    app.add_flag("--other");
+    auto other = app.add_flag("--other");
     ASSERT_NO_THROW(cat->excludes("--other"));
-    EXPECT_THROW(cat->excludes("--other"), CLI::OptionAlreadyAdded);
+    ASSERT_NO_THROW(other->excludes("--cat"));
 }
 
 TEST_F(TApp, CheckName) {
diff --git a/packages/CLI11/tests/HelpTest.cpp b/packages/CLI11/tests/HelpTest.cpp
index 60092d2d3..52b566afb 100644
--- a/packages/CLI11/tests/HelpTest.cpp
+++ b/packages/CLI11/tests/HelpTest.cpp
@@ -1,4 +1,4 @@
-#ifdef CLI_SINGLE_FILE
+#ifdef CLI11_SINGLE_FILE
 #include "CLI11.hpp"
 #else
 #include "CLI/CLI.hpp"
@@ -203,6 +203,17 @@ TEST(THelp, ExcludesPositional) {
     EXPECT_THAT(help, HasSubstr("Excludes: op1"));
 }
 
+TEST(THelp, ExcludesSymmetric) {
+    CLI::App app{"My prog"};
+
+    CLI::Option *op1 = app.add_flag("--op1");
+    app.add_flag("--op2")->excludes(op1);
+
+    std::string help = app.help();
+
+    EXPECT_THAT(help, HasSubstr("Excludes: --op2"));
+}
+
 TEST(THelp, ManualSetters) {
 
     CLI::App app{"My prog"};
diff --git a/packages/CLI11/tests/HelpersTest.cpp b/packages/CLI11/tests/HelpersTest.cpp
index 0f6d87a60..281b8f6df 100644
--- a/packages/CLI11/tests/HelpersTest.cpp
+++ b/packages/CLI11/tests/HelpersTest.cpp
@@ -415,8 +415,8 @@ TEST(Types, LexicalCastParsable) {
 
     std::complex<double> output;
     EXPECT_TRUE(CLI::detail::lexical_cast(input, output));
-    EXPECT_EQ(output.real(), 4.2); // Doing this in one go sometimes has trouble
-    EXPECT_EQ(output.imag(), 7.3); // on clang + c++4.8 due to missing const
+    EXPECT_DOUBLE_EQ(output.real(), 4.2); // Doing this in one go sometimes has trouble
+    EXPECT_DOUBLE_EQ(output.imag(), 7.3); // on clang + c++4.8 due to missing const
 
     EXPECT_FALSE(CLI::detail::lexical_cast(fail_input, output));
     EXPECT_FALSE(CLI::detail::lexical_cast(extra_input, output));
diff --git a/packages/CLI11/tests/NewParseTest.cpp b/packages/CLI11/tests/NewParseTest.cpp
index 5c38870fc..a465618f4 100644
--- a/packages/CLI11/tests/NewParseTest.cpp
+++ b/packages/CLI11/tests/NewParseTest.cpp
@@ -34,8 +34,8 @@ TEST_F(TApp, AddingComplexParser) {
 
     run();
 
-    EXPECT_EQ(1.5, comp.real());
-    EXPECT_EQ(2.5, comp.imag());
+    EXPECT_DOUBLE_EQ(1.5, comp.real());
+    EXPECT_DOUBLE_EQ(2.5, comp.imag());
 }
 
 TEST_F(TApp, DefaultComplex) {
@@ -48,13 +48,13 @@ TEST_F(TApp, DefaultComplex) {
     EXPECT_THAT(help, HasSubstr("1"));
     EXPECT_THAT(help, HasSubstr("2"));
 
-    EXPECT_EQ(1, comp.real());
-    EXPECT_EQ(2, comp.imag());
+    EXPECT_DOUBLE_EQ(1, comp.real());
+    EXPECT_DOUBLE_EQ(2, comp.imag());
 
     run();
 
-    EXPECT_EQ(4, comp.real());
-    EXPECT_EQ(3, comp.imag());
+    EXPECT_DOUBLE_EQ(4, comp.real());
+    EXPECT_DOUBLE_EQ(3, comp.imag());
 }
 
 TEST_F(TApp, BuiltinComplex) {
@@ -68,13 +68,13 @@ TEST_F(TApp, BuiltinComplex) {
     EXPECT_THAT(help, HasSubstr("2"));
     EXPECT_THAT(help, HasSubstr("COMPLEX"));
 
-    EXPECT_EQ(1, comp.real());
-    EXPECT_EQ(2, comp.imag());
+    EXPECT_DOUBLE_EQ(1, comp.real());
+    EXPECT_DOUBLE_EQ(2, comp.imag());
 
     run();
 
-    EXPECT_EQ(4, comp.real());
-    EXPECT_EQ(3, comp.imag());
+    EXPECT_DOUBLE_EQ(4, comp.real());
+    EXPECT_DOUBLE_EQ(3, comp.imag());
 }
 
 TEST_F(TApp, BuiltinComplexIgnoreI) {
@@ -85,8 +85,8 @@ TEST_F(TApp, BuiltinComplexIgnoreI) {
 
     run();
 
-    EXPECT_EQ(4, comp.real());
-    EXPECT_EQ(3, comp.imag());
+    EXPECT_DOUBLE_EQ(4, comp.real());
+    EXPECT_DOUBLE_EQ(3, comp.imag());
 }
 
 TEST_F(TApp, BuiltinComplexFail) {
diff --git a/packages/CLI11/tests/OptionalTest.cpp b/packages/CLI11/tests/OptionalTest.cpp
new file mode 100644
index 000000000..305f42746
--- /dev/null
+++ b/packages/CLI11/tests/OptionalTest.cpp
@@ -0,0 +1,31 @@
+#include <cstdlib>
+#include <iostream>
+
+#include "app_helper.hpp"
+
+#ifdef CLI11_OPTIONAL
+
+TEST_F(TApp, OptionalTest) {
+    CLI::optional<int> opt;
+    app.add_option("-c,--count", opt);
+    run();
+    EXPECT_FALSE(opt);
+
+    app.reset();
+    args = {"-c", "1"};
+    run();
+    EXPECT_TRUE(opt);
+    EXPECT_EQ(*opt, 1);
+
+    app.reset();
+    args = {"--count", "3"};
+    run();
+    EXPECT_TRUE(opt);
+    EXPECT_EQ(*opt, 3);
+}
+
+#else
+
+TEST_F(TApp, DISABLED_OptionalTest) {}
+
+#endif
diff --git a/packages/CLI11/tests/SimpleTest.cpp b/packages/CLI11/tests/SimpleTest.cpp
index bc1f1ba0d..d87495f3e 100644
--- a/packages/CLI11/tests/SimpleTest.cpp
+++ b/packages/CLI11/tests/SimpleTest.cpp
@@ -1,4 +1,4 @@
-#ifdef CLI_SINGLE_FILE
+#ifdef CLI11_SINGLE_FILE
 #include "CLI11.hpp"
 #else
 #include "CLI/CLI.hpp"
diff --git a/packages/CLI11/tests/app_helper.hpp b/packages/CLI11/tests/app_helper.hpp
index 49ef7554a..4280cc9e8 100644
--- a/packages/CLI11/tests/app_helper.hpp
+++ b/packages/CLI11/tests/app_helper.hpp
@@ -1,6 +1,6 @@
 #pragma once
 
-#ifdef CLI_SINGLE_FILE
+#ifdef CLI11_SINGLE_FILE
 #include "CLI11.hpp"
 #else
 #include "CLI/CLI.hpp"
diff --git a/packages/CLI11/tests/informational.cpp b/packages/CLI11/tests/informational.cpp
new file mode 100644
index 000000000..89c73ff9a
--- /dev/null
+++ b/packages/CLI11/tests/informational.cpp
@@ -0,0 +1,50 @@
+#ifdef CLI11_SINGLE_FILE
+#include "CLI11.hpp"
+#else
+#include "CLI/CLI.hpp"
+#endif
+
+#include <iostream>
+
+int main() {
+    std::cout << "\nCLI11 information:\n";
+
+    std::cout << "  C++ standard: ";
+#if defined(CLI11_CPP20)
+    std::cout << 20;
+#elif defined(CLI11_CPP17)
+    std::cout << 17;
+#elif defined(CLI11_CPP14)
+    std::cout << 14;
+#else
+    std::cout << 11;
+#endif
+    std::cout << "\n";
+
+    std::cout << "  __has_include: ";
+#ifdef __has_include
+    std::cout << "yes\n";
+#else
+    std::cout << "no\n";
+#endif
+
+#ifdef CLI11_OPTIONAL
+    std::cout << "  [Available as CLI::optional]";
+#else
+    std::cout << "  No optional library found\n";
+#endif
+
+#ifdef CLI11_STD_OPTIONAL
+    std::cout << "  std::optional support active\n";
+#endif
+
+#ifdef CLI11_EXPERIMENTAL_OPTIONAL
+    std::cout << "  std::experimental::optional support active\n";
+#endif
+
+#ifdef CLI11_BOOST_OPTIONAL
+    std::cout << "  boost::optional support active\n";
+#endif
+
+    std::cout << std::endl;
+}
-- 
GitLab