Fuchsia OS fxl::CommandLineFromArgcArgv() usage? - fuchsia

Fuchsia OS > Guides > Syslog has this example:
#include "src/lib/fsl/syslogger/init.h"
#include "src/lib/fxl/command_line.h"
int main(int argc, char** argv) {
auto command_line = fxl::CommandLineFromArgcArgv(argc, argv);
fsl::InitLoggerFromCommandLine(command_line, {"my_program"});
}
Fuchsia OS > Reference does not have FXL listed:
A search of the Fuchsia Project site has one additional example that has fxl::CommandLineFromArgcArgv().
Where do I find arguments, return value and other details on fxl::CommandLineFromArgcArgv()?

The fxl API is not documented as part of the official Fuchsia reference (yet).
From the readme in the fxl directory (link):
In an ideal world, FXL wouldn‘t exist and we could use the C++ standard library’s building blocks. [...] We‘d like to keep FXL small and focused on the problem of “fixing” the C++ standard library, which means you probably shouldn’t put your thing in FXL unless it is related to a particular deficiency of the C++ standard library.
Based on this statement, it seems fxl is not set up as a long-term project, but rather is meant to become empty/obsolete, when the C++ standard library has been sufficiently adapted. It is possible that documentation effort has been limited for this reason.
We have to rely on the documentation provided directly in the header (link):
// Builds a |CommandLine| from the usual argc/argv.
inline CommandLine CommandLineFromArgcArgv(int argc, const char* const* argv)
The CommandLine class is defined in the same header. According to the comments, it distinguishes between optional and positional args. Optional arguments are of the form --key=value or --key (with no value), but not --key value. The positional arguments begin with the first argument not of this form (or the special -- separator).
The CommandLine member functions are:
Accessing the program name (from argv[0]):
bool has_argv0() const;
const std::string& argv0() const;
Accessing the optional and positional arguments (Option being a simple struct with members std::string name / std::string value):
const std::vector<Option>& options() const;
const std::vector<std::string>& positional_args() const;
Comparison:
bool operator==(const CommandLine& other) const;
bool operator!=(const CommandLine& other) const;
Accessing optional arguments:
bool HasOption(StringView name, size_t* index = nullptr) const;
bool GetOptionValue(StringView name, std::string* value) const;
std::vector<StringView> GetOptionValues(StringView name) const;
std::string GetOptionValueWithDefault(StringView name, StringView default_value) const;
We can write the following example program (uses structured-binding syntax):
#include <iostream>
#include "src/lib/fxl/command_line.h"
int main(int argc, char** argv) {
const auto cl = fxl::CommandLineFromArgcArgv(argc, argv);
std::cout << "Program name = " << cl.argv0() << std::endl;
std::cout << "Optional: " << cl.options().size() << std::endl;
for (const auto& [name,value] : cl.options()) {
std::cout << name << " -> " << value << std::endl;
}
std::cout << "Positional: " << cl.positional_args().size() << std::endl;
for (const auto& arg : cl.positional_args()) {
std::cout << arg << std::endl;
}
return 0;
}
After compiling the program (based on this answer), we can get the following output (demonstrating how first positional argument filename turns all following arguments into positional arguments):
$ hello_world_cpp --k1=v1 --k2 --k3=v3 filename --k4=v4
Program name = hello_world_cpp
Optional: 3
k1 -> v1
k2 ->
k3 -> v3
Positional: 2
filename
--k4=v4
Demonstrating -- as a separator:
$ hello_world_cpp --k1=v1 -- --k2=v2
Program name = hello_world_cpp
Optional: 1
k1=v1
Positional: 1
--k2=v2
We could do simple argument parsing using HasOption:
size_t index;
if (cl.HasOption("key", &index)) {
handle_key(cl.options.at(index).value);
}
Adding this to our program and calling it with --key=abc would then pass abc to handle_key.

Related

Can you add null terminators to a C++11 string and iterate over them?

In C++11, is it legal to put null terminators in a C++11 string and then iterate over the entire length of the string?
#include <string>
#include <iostream>
int main(int argc, char** argv) {
std::string s("\0\0hello\0world\n");
for (char c : s) {
std::cout << " " << (unsigned int)c;
}
std::cout << std::endl;
return 0;
}
Yes, you can, but you need to tell the constructor how many characters you are passing. Otherwise, the constructor will try determining the length by searching for null terminator (i.e. the way the strlen does it), and it is going to get a wrong answer.
std::string s("\0\0hello\0world\n", 14);
Demo

Issue with basename

So I am having an issue using basename for one of my programming assignments for school
I have tried getting a simplier version of it working -- I got it working however, still confused exactly what I am supposed to do in this case
// $Id: util.cpp,v 1.1 2016-06-14 18:19:17-07 - - $
#include <libgen.h>
#include <cstring>
using namespace std;
#include "util.h"
ydc_exn::ydc_exn (const string& what): runtime_error (what) {
}
string exec::execname_; // Must be initialized from main().
int exec::status_ = EXIT_SUCCESS;
void exec::execname (const string& argv0) {
execname_ = basename (argv0.c_str());
cout << boolalpha;
cerr << boolalpha;
DEBUGF ('Y', "execname = " << execname_);
}
void exec::status (int new_status) {
new_status &= 0xFF;
if (status_ < new_status) status_ = new_status;
}
ostream& note() {
return cerr << exec::execname() << ": ";
}
ostream& error() {
exec::status (EXIT_FAILURE);
return note();
}
Just trying to get the code to compile --- my error message in c++ is:
'
util.cpp:15:16: error: no matching function for call to 'basename'
execname_ = basename (argv0.c_str());
^~~~~~~~
/usr/include/libgen.h:40:7: note: candidate function not viable: 1st argument ('const std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>
>::value_type *' (aka 'const char *')) would lose const qualifier
char *basename(char *);
^
1 error generated.
make: *** [util.o] Error 1'
basename takes char* as argument, which is not const, meaning the function is allowed to modify the value.
const string& argv0 is const, meaning the value of argv0 must not be modified.
Thus you are not allowed to call basename with argv0.c_str() as parameter, as that would violate the const qualifier.
The error message is clear: 1st argument ... would lose const qualifier.
So either change argv0 to not be const (probably not a good idea), or change basename to take a const char* parameter (probably the better idea), or change basename to work with std::string instead of char* like the rest of your code (probably the best idea).
So apparently basename is a unix function that you cannot change. (Thanks Nevin!) From the manpage:
Both dirname() and basename() may modify the contents of path, so it may be desirable to pass a copy when calling one of these functions.
In that case I recommend creating a copy of argv0. The simplest way of doing this would be to change the signature of execname to this:
void exec::execname(std::string argv0)
I think that your central problem is including libgen.h as well as cstring. If you look at the prototypes for basename in those files, they're different. If you're building this on linux, you'll see a comment in the libgen.h version which should be enlightening.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html and
https://linux.die.net/man/3/basename are useful here too.
I suggest removing the #include <libgen.h> and trying again.

Different behavior of Visual Studio and gcc when compiling variadic templates program

I'm playing with C++11's variadic templates, and here is my code:
#include "iostream"
void func(){
std::cout << std::endl;
}
template< typename ...Params> void func(int x, Params... params){
std::cout << " int " << x;
func(params...);
}
template< typename ...Params> void func(float x, Params... params){
std::cout << " float " << x;
func(params...);
}
template< typename ...Params> void func(const char* x, Params... params){
std::cout << " const char* " << x;
func(params...);
}
int main(int argc, char* argv[])
{
func(3.14f, 5, "Test");
getchar();
return 0;
}
The code above can be compiled and run on Visual Studio 2013 without any problem, but if I compile it with gcc 4.6.3 (I don't have gcc environment and using online service like repl.it), this code will produce error like this:
main.cpp: In instantiation of 'void func(int, Params ...) [with Params = {const char*}]':
main.cpp:15:6: required from 'void func(float, Params ...) [with Params = {int, const char*}]'
main.cpp:24:23: required from here
main.cpp:11:6: error: no matching function for call to 'func(const char*&)'
func(params...);
~~~~^~~~~~~~~~~
main.cpp:5:6: note: candidate: void func()
void func(){
^~~~
main.cpp:5:6: note: candidate expects 0 arguments, 1 provided
main.cpp:9:36: note: candidate: template<class ... Params> void func(int, Params ...)
template< typename ...Params> void func(int x, Params... params){
^~~~
main.cpp:9:36: note: template argument deduction/substitution failed:
main.cpp:11:6: note: cannot convert 'params#0' (type 'const char*') to type 'int'
func(params...);
~~~~^~~~~~~~~~~
exit status 1
Whose behavior is right? Is this code has some problem I don't acknowledge or this is a bug of gcc?
BTW: If I change func(3.14f,5,"test") into func(3.14f,5) then gcc can compile this code as well.
gcc behaviour is right.
Roughly speaking, when you instantiate a template, the instantiation needs to be legal C++ code when placed where the original template definition was found. (More precisely, all names except so-called dependent names need to be resolvable at the point of template definition).
In your case, the first template instantiates to an equivalent of
void func(int x, const char *params0){
std::cout << " int " << x;
func(params0);
}
and the last call is not valid at the point of template definition. Indeed, the template that can handle the call does not get declared until later in the code.
VC++ is known for its non-compliant handling of templates: it only checks validity of the instantiation at the point of instantiation, not at the point of the original template definition. This code illustrates it nicely.
To bring your code to compliance, first forward-declare the templates and then define them.

Different results on a variadic template example among gcc, clang and msvc - can anyone explain?

I needed to make a function that takes a function pointer with variable arguments and some fixed arguments after them and could not make it work on Visual Studio 2013. I assumed that maybe Visual Studio 2013 was missing something which is often a case and made a minimal example that did what I needed and tried it against gcc and clang. And I got totally different results on all three compilers. So the questions which I'd like to resolve are:
Is my example valid at all? If not what am I doing wrong?
If my example is valid, any hints on the behavior of gcc and clang (lets count msvc out since it is a black box)?
The example:
#include <iostream>
struct foo
{
void work(int first, int second, int third)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << std::endl;
}
void work_with_double(double first, int second, int third, int fourth)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << ",3: " << fourth << std::endl;
}
};
template<typename ... argument_types>
void invoke_foo(foo* instance, int first, int second, int third, void (foo::*method)(argument_types ... arguments, int, int, int), argument_types ... arguments)
{
(instance->*method)(arguments ..., first, second, third);
}
int main(int argc, char** argv)
{
foo instance;
invoke_foo(&instance, 1, 2, 3, &foo::work); // gcc ok, clang err, msvc 2013 err
invoke_foo<>(&instance, 1, 2, 3, &foo::work); // gcc ok, clang err, msvc 2013 err
invoke_foo(&instance, 1, 2, 3, &foo::work_with_double, 1.0); // gcc err, clang ok, msvc 2013 err
invoke_foo<double>(&instance, 1, 2, 3, &foo::work_with_double, 1.0); // gcc err, clang err, msvc 2013 ok
return 0;
}
Modified snippet that makes Visual Studio 2015 (w/o updates) crash
If invoke_foo is made as a member function of an object, Visual Studio 2015 crashes.
#include <iostream>
#include <memory>
struct foo
{
void work(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << std::endl;
}
void work_with_double(double firstExtra, int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight)
{
std::cout << "0: " << first << ",1: " << second << ",2: " << third << ",3: " << fourth << std::endl;
}
};
struct bar
{
};
struct wrapper
{
template <typename T> struct non_deduced { using type = T; };
template <typename T> using non_deduced_t = typename non_deduced<T>::type;
template<typename ... argument_types>
std::shared_ptr<bar> invoke_foo(int first, int second, int third, int fourth, int fifth, int sixth, int seventh, int eight, void (foo::*method)(non_deduced_t<argument_types>... arguments, int, int, int, int, int, int, int, int), argument_types ... arguments)
{
(foo_.get()->*method)(arguments ..., first, second, third, fourth, fifth, sixth, seventh, eight);
return nullptr;
}
std::unique_ptr<foo> foo_ = std::move(std::unique_ptr<foo>(new foo));
};
int main(int argc, char** argv)
{
wrapper instance;
instance.invoke_foo(1, 2, 3, 4, 5, 6, 7, 8, &foo::work);
instance.invoke_foo(1, 2, 3, 4, 5, 6, 7, 8, &foo::work_with_double, 1.0);
}
The problem in each case is that the compiler is trying to infer argument_types from the method argument, which is illegal as variadic template parameters can only be inferred when they are at the end of an argument list.
void (foo::*method)(argument_types ... arguments, int, int, int)
^^^^^^^^^^^^^^^^^^ can't infer here
^^^^^^^^^^^^^^^ because of these
The workaround is to protect argument_types from being deduced in this context, using a helper like identity:
template<class T> struct identity { using type = T; };
template<class T> using identity_t = typename identity<T>::type;
// ...
template<typename ... argument_types>
void invoke_foo(foo* instance, int first, int second, int third,
void (foo::*method)(identity_t<argument_types> ... arguments, int, int, int), argument_types ... arguments)
// ^^^^^^^^^^^ fix here
Is this a bug in your code, or in the compilers? Actually, it's a bug in the compilers (yes, all of them); the question is whether a parameter pack appearing within a function type and not at the end of an argument list is a non-deduced context. The relevant part of the standard is [temp.deduct.type], which states:
5 - The non-deduced contexts are: [...]
A function parameter pack that does not occur at the end of the parameter-declaration-list.
6 - When a type name is specified in a way that includes a non-deduced context, all of the types that comprise that type name are also non-deduced. However, a compound type can include both deduced and non-deduced types.
Here, argument_types is in a non-deduced context when deducing the type of method, but a deduced context when deducing the types for the trailing arguments of invoke_foo.
Another compiler you could test is ICC (Intel C++ Compiler); ICC rejects the first two forms and accepts the last two, the exact opposite to gcc. The reason that compilers can be so different in their behavior is that dealing with this kind of code is essentially a matter of error handling, specifically recognising when template parameters appear in non-deduced contexts and using the types deduced elsewhere instead. The compilers are (each in their own way) recognising that argument_types cannot be deduced within method, but failing to realise or accept that it can be deduced elsewhere.
Specifically, it appears that:
gcc assumes that if it cannot deduce argument_types from method, it must be empty;
clang assumes that if argument_types is deduced to be empty or explicitly specified, this must be an error;
MSVC is unable to let the deduction of argument_types override the failure to deduce it, but is OK if it is explicitly specified;
ICC assumes that if argument_types is deduced to be empty, this must be an error.

std::initializer_list with Multiple Types

I'm having trouble with std::initializer_list. I reduced it down to a simple example:
#include <initializer_list>
#include <cstdio>
class Test {
public:
template <typename type> Test(const std::initializer_list<type>& args) {}
};
int main(int argc, char* argv[]) {
Test({1,2});
getchar();
return 0;
}
When compiled using g++ test_initializer.cpp -std=c++0x, it compiles and runs well. However, if line 11 is changed to Test({1,2.0});, one gets:
ian#<host>:~/Desktop$ g++ test_initializer.cpp -std=c++0x
test_initializer.cpp: In function ‘int main(int, char**)’:
test_initializer.cpp:11:14: error: no matching function for call to ‘Test::Test(<brace-enclosed initializer list>)’
test_initializer.cpp:11:14: note: candidates are:
test_initializer.cpp:7:28: note: template<class type> Test::Test(const std::initializer_list<_Tp>&)
test_initializer.cpp:5:7: note: constexpr Test::Test(const Test&)
test_initializer.cpp:5:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const Test&’
test_initializer.cpp:5:7: note: constexpr Test::Test(Test&&)
test_initializer.cpp:5:7: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘Test&&’
I suspect this happens because the compiler can't figure out what type to make the initializer list. Is there a way to fix the example so that it works with different types (and still uses initializer lists)?
An std::initializer_list takes only one type. If you need different types, you can use variadic templates:
template<typename... Args>
Test(Args&&... args);
/* ... */
int main()
{
Test(1, 2.0);
}
Would a std::tuple<int.double> work for the OP? If the code will always have a int followed by a double, then the OP could get strict type-checking for all arguments, which the variable arguments solution does not allow. The std::tuple<>, however, would not work for any number or order of values, so may not be appropriate for all use cases.
Let the initializer_list hold the most arbitrary pointers, void*, and do your own casting from there. Here is an example.
#include <initializer_list>
#include <iostream>
using std::initializer_list;
using std::cout;
using std::endl;
class Person {
private:
string _name;
int _age;
public:
Person(initializer_list<void*> init_list) {
auto it = init_list.begin();
_name = *((string*)(*it));
it++;
_age = *((int*)(*it));
}
void print() {
cout << "name: " << _name << ". age: " << _age << endl;
}
};
int main(void) {
string name{"Vanderbutenburg};
int age{23};
Person p{&name,&age};
p.print(); // "name: Vanderbutenburg. age: 23"
return 0;
}

Resources