Commit 76bd60dc17ca514f2febb49382b38d526d5502a5

Authored by Jarryd Beck
1 parent e792760a

Add support for std::optional

Fixes #93. This adds C++17 only support for `std::optional` values for
command line parameters.
.travis.yml
@@ -12,7 +12,8 @@ matrix: @@ -12,7 +12,8 @@ matrix:
12 packages: 12 packages:
13 - g++-4.9 13 - g++-4.9
14 sources: &sources 14 sources: &sources
15 - - llvm-toolchain-precise-3.8 15 + - llvm-toolchain-trusty-3.8
  16 + - llvm-toolchain-trusty-5.0
16 - ubuntu-toolchain-r-test 17 - ubuntu-toolchain-r-test
17 - os: linux 18 - os: linux
18 env: COMPILER=g++-4.9 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes 19 env: COMPILER=g++-4.9 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
@@ -27,9 +28,7 @@ matrix: @@ -27,9 +28,7 @@ matrix:
27 apt: 28 apt:
28 packages: 29 packages:
29 - g++-5 30 - g++-5
30 - sources: &sources  
31 - - llvm-toolchain-precise-3.8  
32 - - ubuntu-toolchain-r-test 31 + sources: *sources
33 - os: linux 32 - os: linux
34 env: COMPILER=g++-5 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes 33 env: COMPILER=g++-5 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes
35 addons: 34 addons:
@@ -53,9 +52,17 @@ matrix: @@ -53,9 +52,17 @@ matrix:
53 - clang-3.8 52 - clang-3.8
54 - libc++-dev 53 - libc++-dev
55 sources: *sources 54 sources: *sources
  55 + - os: linux
  56 + env: COMPILER=clang++-5.0 CMAKE_OPTIONS=-DCXXOPTS_CXX_STANDARD=17
  57 + addons:
  58 + apt:
  59 + packages:
  60 + - clang-5.0
  61 + - g++-5
  62 + sources: *sources
56 script: > 63 script: >
57 cmake -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER 64 cmake -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER
58 - -DCMAKE_CXX_FLAGS=$CXXFLAGS $UNICODE_OPTIONS . 65 + -DCMAKE_CXX_FLAGS=$CXXFLAGS $UNICODE_OPTIONS $CMAKE_OPTIONS .
59 && make && make ARGS=--output-on-failure test 66 && make && make ARGS=--output-on-failure test
60 67
61 before_install: 68 before_install:
CMakeLists.txt
@@ -28,8 +28,14 @@ option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON) @@ -28,8 +28,14 @@ option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON)
28 option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" OFF) 28 option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" OFF)
29 29
30 # request c++11 without gnu extension for the whole project and enable more warnings 30 # request c++11 without gnu extension for the whole project and enable more warnings
31 -set(CMAKE_CXX_STANDARD 11) 31 +if (CXXOPTS_CXX_STANDARD)
  32 + set(CMAKE_CXX_STANDARD ${CXXOPTS_CXX_STANDARD})
  33 +else()
  34 + set(CMAKE_CXX_STANDARD 11)
  35 +endif()
  36 +
32 set(CMAKE_CXX_EXTENSIONS OFF) 37 set(CMAKE_CXX_EXTENSIONS OFF)
  38 +
33 if(MSVC) 39 if(MSVC)
34 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") 40 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2")
35 elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") 41 elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
include/cxxopts.hpp
@@ -38,6 +38,11 @@ THE SOFTWARE. @@ -38,6 +38,11 @@ THE SOFTWARE.
38 #include <unordered_set> 38 #include <unordered_set>
39 #include <vector> 39 #include <vector>
40 40
  41 +#ifdef __cpp_lib_optional
  42 +#include <optional>
  43 +#define CXXOPTS_HAS_OPTIONAL
  44 +#endif
  45 +
41 namespace cxxopts 46 namespace cxxopts
42 { 47 {
43 static constexpr struct { 48 static constexpr struct {
@@ -697,6 +702,17 @@ namespace cxxopts @@ -697,6 +702,17 @@ namespace cxxopts
697 value.push_back(v); 702 value.push_back(v);
698 } 703 }
699 704
  705 +#ifdef CXXOPTS_HAS_OPTIONAL
  706 + template <typename T>
  707 + void
  708 + parse_value(const std::string& text, std::optional<T>& value)
  709 + {
  710 + T result;
  711 + parse_value(text, result);
  712 + value = std::move(result);
  713 + }
  714 +#endif
  715 +
700 template <typename T> 716 template <typename T>
701 struct type_is_container 717 struct type_is_container
702 { 718 {
test/options.cpp
@@ -454,3 +454,22 @@ TEST_CASE(&quot;Booleans&quot;, &quot;[boolean]&quot;) { @@ -454,3 +454,22 @@ TEST_CASE(&quot;Booleans&quot;, &quot;[boolean]&quot;) {
454 454
455 REQUIRE(result.count("others") == 1); 455 REQUIRE(result.count("others") == 1);
456 } 456 }
  457 +
  458 +#ifdef CXXOPTS_HAS_OPTIONAL
  459 +TEST_CASE("std::optional", "[optional]") {
  460 + std::optional<std::string> optional;
  461 + cxxopts::Options options("optional", " - tests optional");
  462 + options.add_options()
  463 + ("optional", "an optional option", cxxopts::value<std::optional<std::string>>(optional));
  464 +
  465 + Argv av({"optional", "--optional", "foo"});
  466 +
  467 + char** argv = av.argv();
  468 + auto argc = av.argc();
  469 +
  470 + options.parse(argc, argv);
  471 +
  472 + REQUIRE(optional.has_value());
  473 + CHECK(*optional == "foo");
  474 +}
  475 +#endif