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::vector
s 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.
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.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).
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.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.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.