Menu

#24 Create another interface for `parse`

Unknown
open
nobody
None
5
2021-10-25
2021-10-21
KOLANICH
No

When designing HydrArgs I have decided that the interface int argc, const char * argv[], is extremily inconvenient for the purpose of stacking CLI parsers, because one has to create std::vectors and manage their memory. So I have designed a somehow better interface.

struct HYDRARGS_API CLIRawArgs{
    using element_type = const char *;
    using SpanT = std::span<element_type>;
    using VectorT = std::vector<element_type>;

    element_type argv0 = nullptr;  ///< argv0, program name
    SpanT argvRest;  ///< array of pointers to CLI args

    VectorT getArgvVector();  ///< Returns an std::vector of pointers to argv. WARNING, vectorSize() - 1 == argc beacause the last element of the vector must be NULL
};

std::span allows to share continious slices of arrays, right from argv, and requires no ownership.
Splititng argv0 from argvRest allows to avoid creating an array.

Unfortunately, for the most of cases I still have to create an array, because almost no librararies use the similar model (but there are some doing the same).

With TClap the issue is more severe. While the rest of libs allow to create the array temporary and dispose it after use, TClap seems to be requiring them to be present for a whole livespan of an object. Though even this doesn't help. Here is my code: https://github.com/HydrArgs/HydrArgs/blob/master/backends/TCLAP.cpp . I have tried swapping order of CLIRawArgs::VectorT tempArgvVec and TCLAP::CmdLine app with no useful effect.

It may make sense to provide an additional parse method, using something similar to the model used in HydrArgs. A method acccepting not argc and argv, but a method accepting argv0 and a span for the rest argvs.

Discussion

  • Daniel Aarno

    Daniel Aarno - 2021-10-24

    I'm not sure exactly what problem you experience, but TCLAP doesn't hold on to any of the argv's. In fact, all the parse(int argc, const char *const *argv) method does is to copy the argv into a temporary vector that is destroyed when the function exits.

    inline void CmdLine::parse(int argc, const char *const *argv) {
        // this step is necessary so that we have easy access to
        // mutable strings.
        std::vector<std::string> args;
        for (int i = 0; i < argc; i++) args.push_back(argv[i]);
    
        parse(args);
    }
    

    Two notes:

    1) You can use CmdLine::parse(std::vector<std::string> &args) instead of messing around with argc/argv. However, do note that this vector will be modified during parsing, so you probably want to make a copy of your input before calling parse - unless you don't need to persist the data in the args vector.

    2) We are not going to use span since we are maintaining compatibility with C++98 for v1.2 and v1.4. If we get around to doing a v2.0 that will most likely target some more modern version of C++ (at least C++11).

     
  • KOLANICH

    KOLANICH - 2021-10-24

    I'm not sure exactly what problem you experience, but TCLAP doesn't hold on to any of the argv's. In fact, all the parse(int argc, const char const argv) method does is to copy the argv into a temporary vector that is destroyed when the function exits.
    You can use CmdLine::parse(std::vector<std::string> &args) instead of messing around with argc/argv. However, do note that this vector will be modified during parsing, so you probably want to make a copy of your input before calling parse - unless you don't need to persist the data in the args vector.

    You are right, the issues is not likely because of that vector and I should have used CmdLine::parse(std::vector<std::string> &args). Thank you for pointing it out, I have missed this.

    2) We are not going to use span since we are maintaining compatibility with C++98 for v1.2 and v1.4. If we get around to doing a v2.0 that will most likely target some more modern version of C++ (at least C++11).

    I wonder if we can anyhow additionally use it and the interface like the one mentioned depending on C++ language version and presence of https://github.com/martinmoene/span-lite (#ifdef NONSTD_SPAN_HPP_INCLUDED)? I mean writing some affected methods as templates (isn't TCLAP currently a header-only library?) , not depending on whether we are using spans, vectors or other collections, and writing other ones the ways their body and signature is chosen based on preprocessor definitions.

     
  • Daniel Aarno

    Daniel Aarno - 2021-10-25

    I think the challenge here is that it adds complexity for a very particular use-case, so it would have to be demonstrated that 1) this is useful for (some portion of) TCLAP's intended audience and 2) the change is simple enough to warrant adding this for everyone + the maintainers.

    So if you can come up with some use-cases for (1) and send a patch for (2) I'll take a look at it.

     

Log in to post a comment.