Multi Value Arg???

Help
2007-05-02
2013-05-28
  • Kevin Orcutt
    Kevin Orcutt
    2007-05-02

    Howdy,
         Is there a way to have a group of value args appear as one flag? i.e.:
    asdf.exe -G 1.2 2.3 3.4 -T 1 blah blah blah...

    I need to pass in a 3-d vector (X component, Y component, and Z component) flagged as -G. along with two or three other parameters.  If the user does not specify the -G then don't look for the three float/double values.

    Any ideas out there???

    Many thanks in advance,

    Kevin Orcutt
    software engineer
    SAEC/kinetic vision

     
    • Daniel Aarno
      Daniel Aarno
      2007-05-02

      I don't think that it is possible, please correct me if I'm wrong. However, you can easily "fake" it by passing a single argument to a value arg and then do some parsing of your own. See example below. Obviously this is not ideal since it takes away some of the type checking and error handling performed by tclap and it may not be intuitive to the user. Perhaps we should consider adding the functionality to have switches take any number of arguments. This could be give as an extra template parameter to the Arg object and would default to 1.

      #include <tclap/CmdLine.h>
      #include <iterator>
      #include <stdexcept>
      #include <algorithm>
      #include <sstream>

      template<typename T> void
      String2Vect(const std::string &s, std::vector<T> &v)
      {
           v.clear();
           std::istringstream iss(s);
           std::istream_iterator<T> isi(iss);
           std::copy(isi, std::istream_iterator<T>(),
                 std::back_inserter(v));
      }

      int
      main(int argc, char * argv[])
      {
           try {
            TCLAP::CmdLine parser("");
            TCLAP::ValueArg<std::string> vect("v", "vect", "3d vector", true,
                              "0 0 0",
                              "A space separated 3d vector",
                              parser);
            parser.parse(argc, argv);

            std::vector<float> v;
            v.reserve(3);
            String2Vect(vect.getValue(), v);
            if (v.size() < 3) {
                 throw std::runtime_error("Too few values");
            } else if (v.size() > 3) {
                 throw std::runtime_error("Too many values");
            }

            std::cout << "Vector is: ";
            std::ostream_iterator<float> osi(std::cout, " ");
            std::copy(v.begin(), v.end(), osi);
            std::cout << std::endl;

           } catch(std::exception &e) {
            std::cerr << "Exception: " << e.what() << std::endl;
            return EXIT_FAILURE;
           }

      }

       
    • Mike Smoot
      Mike Smoot
      2007-05-04

      Another option would be to have 3 separate value args: --Gx --Gy --Gz and then use a Constraint object with each that checks that all 3 are set.  That might have issues too, but it's a thought. 

      In any case, there isn't a way for a single ValueArg -G to read in three values in this form "-G one two three".  The only way would be as a MultiValueArg "-G one -G two -G three".  This is because the parser wouldn't be able to distinguish "two three" from any unlabeled args.

       

  • Anonymous
    2012-10-24

    I came in here to ask exactly this question, too. It's a fairly common command line pattern, and it makes more logical sense in many use cases than a multiArg. This question is a good example, because the data following G makes a set, and you would lose the sense of "setness" by doing -G a -G b -G c.  One of your SF competitors, ezOptionParser, supports it, just as a point of interest.