3 ms·
It's making an object of type "shell" with true as a constructor argument. But I believe it works like named parameters in that you could use any combination of
by jsnell 11y ago
It's making an object of type "shell" with true as a constructor argument. But I believe it works like named parameters in that you could use any combination of parameters in any order. This works by making sp::call a variadic template, with the parameter "parsing" happening at compile time based on the types of these wrapper objects.
- souperhanz 11y agoExactly. I imagine it's something like the following: #include <iostream> #include <string> #include <utility> namespace sp { template <typename T> struct option { template <typename U> option(U&& u) : mValue(std::forward<U>(u)) {} const T& getValue() const { return mValue; } private: T mValue; }; struct shell : option<bool> { using option<bool>::option; }; struct output : option<std::string> { using option<std::string>::option; }; struct options { bool mShell; std::string mOutput; }; void applyOpt(options& opts, const shell& opt) { opts.mShell = opt.getValue(); std::cout << "shell=" << (opts.mShell ? "true" : "false") << '\n'; } void applyOpt(options& opts, const output& opt) { opts.mOutput = opt.getValue(); std::cout << "output=" << opts.mOutput << '\n'; } void applyOpts(options&) {} template <typename HeadOpt, typename... TailOpts> void applyOpts(options& opts, HeadOpt&& headOpt, TailOpts&&... tailOpts) { applyOpt(opts, std::forward<HeadOpt>(headOpt)); applyOpts(opts, std::forward<TailOpts>(tailOpts)...); } template <typename... Opts> int call(std::initializer_list<const char*> args, Opts&&... opts) { std::cout << "args="; const char* sep = ""; for (auto&& s : args) { std::cout << sep << s; sep = " "; } std::cout << '\n'; options options; applyOpts(options, std::forward<Opts>(opts)...); return 0; } } int main() { sp::call({"ls", "-l"}, sp::shell{true}, sp::output{"foo.txt"}); return 0; }
- ant6n 11y agoOh neat. Also thanks for reducing the use to a 'small' example. Why does the author use a struct and "shell{true}" rather than creating a function or a class that would allow "shell(true)". Love for braces? Performance? EDIT: also I wonder whether there's a way to create helper definitions to allow defining named parameters like this in a more concise way. This recursive template expansion business tends to result in long code.
- ant6n 11y agoOk, so it seems the use of braces (use of "Uniform initialization syntax") in constructors is to reduce the ambiguity with declaring functions and declaring+initializing variables. This wiki entry has more: https://en.wikipedia.org/wiki/Most_vexing_parse https://en.wikipedia.org/wiki/Most_vexing_parse
- souperhanz 11y agoIt's a very good day. I get to just say "exactly" again. :)
- Fede_V 11y agoThanks for taking the time to explain that :)