diff --git a/include/CLI/Error.hpp b/include/CLI/Error.hpp
index 0a6a73d..09104a6 100644
--- a/include/CLI/Error.hpp
+++ b/include/CLI/Error.hpp
@@ -105,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/include/CLI/Option.hpp b/include/CLI/Option.hpp
index 62d7e58..dd61dfd 100644
--- a/include/CLI/Option.hpp
+++ b/include/CLI/Option.hpp
@@ -383,8 +383,8 @@ class Option : public OptionBase {
/// Take the last argument if given multiple times (or another policy)
Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
- // TODO: This can support multiple options
- if(get_type_size() != 0 && get_expected() != 1)
+
+ if(get_items_expected() < 0)
throw IncorrectConstruction::MultiOptionPolicy(single_name());
multi_option_policy_ = value;
return this;
@@ -400,12 +400,25 @@ class Option : public OptionBase {
/// The number of times the option expects to be included
int get_expected() const { return expected_; }
- /// The total number of expected values (including the type)
+ /// \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 {
- // type_size == 0, return 0
- // type_size > 1, return type_size_
- // type_size < 0, return -type_size * expected;
- return type_size_ < 0 ? -1 * type_size_ * expected_ : type_size_;
+ 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
@@ -525,14 +538,18 @@ class Option : public OptionBase {
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(results_.size()));
+
// Operation depends on the policy setting
if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
- // TODO: add non-1 size arguments here
- 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) {
diff --git a/tests/AppTest.cpp b/tests/AppTest.cpp
index 03a50f2..c9a398b 100644
--- a/tests/AppTest.cpp
+++ b/tests/AppTest.cpp
@@ -1,5 +1,6 @@
#include "app_helper.hpp"
#include
+#include
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 vals;
+ app.add_option("--long", vals)->expected(2)->take_last();
+
+ args = {"--long", "1", "2", "3"};
+
+ run();
+
+ EXPECT_EQ(vals, std::vector({2, 3}));
+}
+
+TEST_F(TApp, TakeFirstOptMulti) {
+ std::vector vals;
+ app.add_option("--long", vals)->expected(2)->take_first();
+
+ args = {"--long", "1", "2", "3"};
+
+ run();
+
+ EXPECT_EQ(vals, std::vector({1, 2}));
+}
+
+TEST_F(TApp, ComplexOptMulti) {
+ std::complex val;
+ app.add_complex("--long", val)->take_first();
+
+ args = {"--long", "1", "2", "3", "4"};
+
+ run();
+
+ EXPECT_FLOAT_EQ(val.real(), 1);
+ EXPECT_FLOAT_EQ(val.imag(), 2);
+}
+
TEST_F(TApp, MissingValueNonRequiredOpt) {
int count;
app.add_option("-c,--count", count);