what does a const char** look like? - c++

I have a class which takes the main command line arguments (eg, -B, -a, etc) and does something with them, but also i would like to be able to instantiate that function without passing the command line arguments, so for example:
constructor:
myClass(int argc, const char **argv){
<initialise class with flags from argv>
}
myClass() : myClass(2, "-B") {}
}
Here i am trying to instantiate myClass with the flag "-B", but it keeps giving me the error:
no known conversion for argument 3 from ‘const char [3]’ to ‘const char**’
so i was wondering what i need to do to pass a value in as const char**?

First level is pointer to first pointer to char *. Second level is pointer to the first const char of c-string.
> cdecl explain "const char ** args"
declare args as pointer to pointer to const char
If you have -std=c++11 available, you can use this example (but it can be rewritten to use old standard):
#include <iostream>
#include <vector>
#include <string>
class test {
public:
test(const std::vector<std::string> & args) {
for (auto & arg : args) {
std::cout << arg << "\n";
}
}
test() : test{{"-B"}} {}
};
int main(int argc, const char ** argv) {
test sth{{argv+1, argc+argv}}; // skip program name here
test sth_else;
}

const char** is pointer to const char*. In your case, you intend to pass multiple arguments as part of argv, so you can pass something like below:
const char* argv[] = {"<program name>", "B"};
myClass m(2, argv);
Note: const char** x & const char* x[] are same. The 2nd syntax is helpful when one wants to "represent" an array.
Here I am giving a way to mimic the main(int, char**) function argument for your internal test. If you want to pass from default constructor to argument constructor then all the above stuff will have to go global.

Related

How do you C++ Vector init in header construct to fill with pointers of a static char const

header file:
#include<vector>
#ifndef FOO_H
#define FOO_H
class Foo
{
public:
Foo(int s) : pegs (s, *TOKEN_EMPTY){}
static char const TOKEN_EMPTY=' ';
protected:
std::vector<char*> pegs;
}
When trying to build I get the error:
error: invalid type argument of unary ‘*’ (have ‘char’)
20 | Foo(int s) : pegs (s, *TOKEN_EMPTY){}
In case it isn't clear, I just want to initialize a C++ vector of pointers that point to a static char const variable.
I'm still checking StackOverflow and online, but I am hopeful someone can help me or lead me in the right direction!
Adding few more points in the answer provided by #Roger.
*TOKEN_EMPTY is incorrect syntax, what you need is address of TOKEN_EMPTY so you need to apply & operator to get address of the variable.
the TOKEN_EMPTY is const char string, so when you apply & operator, it would return const char*. So you need to update your vector to hold const char *.
Alternatively you can also use typecast operation to convert const char * to char * but it could possibly lead to issues where you can potentially modify the value of const char.
Here is a sample code.
#include <iostream>
#include <vector>
class Foo
{
public:
Foo(int s) : pegs (s, &TOKEN_EMPTY){}
static char const TOKEN_EMPTY=' ';
protected:
std::vector<const char*> pegs;
};
int main() {
// ues class Foo
return 0;
}
Changed to &TOKEN_EMPTY and had to use:
std::vector<const char*> pegs;

Why passing char* to a string argument generates a compilation error? [duplicate]

This question already has answers here:
Pass a string in C++
(8 answers)
Closed 5 years ago.
I was prototyping with the following code.
#include <vector>
#include <iostream>
#include <algorithm>
#include <string>
template<class container, class value> class Add {
public:
Add(){};
~Add(){};
void add_value(container& cont, value& val){
std::for_each(cont.begin(), cont.end(), [&val](value& v){v +=val;});
};
};
int main(int argc, char const *argv[])
{
Add<std::vector<std::string>, std::string> a;
std::vector<std::string> vec = {"a", "b", "c", "d"};
std::string foo= "1";
a.add_value(vec, foo); // compiles fine
a.add_value(vec, "1"); // generates an error
return 0;
}
and i got the following error
template.cpp:28:25: error: invalid initialization of non-const reference of type ‘std::__cxx11::basic_string<char>&’ from an rvalue of type ‘std::__cxx11::basic_string<char>’
Why it's not possible to pass a char* to a string argument ?
As far as i know an implicit conversion will be executed in order to convert the char* to std::string and the result will be passed to the function.
You defined the add_value as following:
void add_value(container& cont, value& val)
Where the string is a non-const reference, the compiler expect this reference to point to a modifiable variable somewhere else.
However, when you pass a const char[], even if this type could be converted to a string (in case it would compile), it is done on the fly and the string is not modifiable. Actually, the char* is not modifiable neither. That is why your code do not compile.
You may define your function as following and it would work:
void add_value(container& cont, const value& val)

Converting std::string to QString in constructor

I cannot understand why std::string converted into QString while passing it to constructor. Here is small example:
class StringHandler
{
private:
QString str;
public:
StringHandler(QString s): str(s) {}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::string str = "string";
QString qstr(str); // it gives error there are no constructor QString(std::string)
StringHandler handler(QString(str));//it does not give an error. Why?
return a.exec();
}
EDIT:
class StringHandler
{
public:
StringHandler(QString s): str(s) {}
QString str;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::string str = "string";
StringHandler handler(QString(str));//Here should be error, but there no error. Why?
qDebug()<<handler.str; //Error is here: request for member 'str' in 'handler', which is of non-class type 'StringHandler(QString)'
return a.exec();
}
Say hello to the most vexing parse.
StringHandler handler(QString(str)); declares a function named handler that takes a QString and returns a StringHandler. Yes. Thanks to the C++ parsing rules.
Now the error message request for member 'str' in 'handler', which is of non-class type 'StringHandler(QString)' makes sense: handler is being treated like a function of type StringHandler(QString) and you're trying to access a member named str in it, but of course functions have no members so the compilation fails.
You can fix this by using the uniform initialization syntax:
StringHandler handler{QString(str)};
The above can't be parsed as a function declaration, and so the compilation should fail for the expected reason: no matching constructor QString(std::string).
For more info, see C++'s most vexing parse again.

std::map with lambda comparator

My below code is giving me compiler error and I an not understanding what wrong I am doing. Can anyone help please?
Basically all I am trying to do is pass a STL map container by reference to a function which would fill it up. This map container also has a comparator lambda associated with it.
#include "stdafx.h"
#include <functional>
#include <map>
using namespace std;
typedef struct _tagAddressBook
{
string strFirstName;
string strLastName;
long nZipCode;
} AddressBook;
void foo(map<string, AddressBook, function<bool(const string&, const string&)>> &myAddressBook)
{
AddressBook addressBookInstance;
addressBookInstance.strFirstName = "Bob";
addressBookInstance.strLastName = "Parker";
addressBookInstance.nZipCode = 12345;
myAddressBook.insert(std::pair<string, AddressBook>(addressBookInstance.strFirstName, addressBookInstance));
}
int _tmain(int argc, _TCHAR* argv[])
{
auto myComparator = [] (const string &strLeft, const string &strRight) { return(strLeft.compare(strRight) <= 0 ? true : false); };
map<string, AddressBook, decltype(myComparator)> myAddressBook(myComparator);
foo(myAddressBook);
return 0;
}
I get the below compilation error on VS2012
Error 1 error C2664: 'foo' : cannot convert parameter 1 from 'std::map<_Kty,_Ty,_Pr>' to 'std::map<_Kty,_Ty,_Pr> &' d:\my projects\mapwithlambdacomparator\mapwithlambdacomparator\mapwithlambdacomparator.cpp 32
2 IntelliSense: a reference of type "std::map<std::string, AddressBook, std::function<bool (const std::string &, const std::string &)>, std::allocator<std::pair<const std::string, AddressBook>>> &" (not const-qualified) cannot be initialized with a value of type "std::map<std::string, AddressBook, lambda []bool (const std::string &strLeft, const std::string &strRight)->bool, std::allocator<std::pair<const std::string, AddressBook>>>" d:\My Projects\MapWithLambdaComparator\MapWithLambdaComparator\MapWithLambdaComparator.cpp 32
Lambda functions are not related to std::function. In fact, each is its own class type. If you want to do what it appears you do, you can do it by template through foo and let deduction sort it out.
template <typename Cmp>
void foo(map<std::string, AddressBook, Cmp> &myAddressBook)
{
AddressBook addressBookInstance;
addressBookInstance.strFirstName = "Bob";
addressBookInstance.strLastName = "Parker";
addressBookInstance.nZipCode = 12345;
myAddressBook.insert(std::pair<string, AddressBook>(addressBookInstance.strFirstName, addressBookInstance));
}
This works on my toolchain, "Apple LLVM version 5.0 (clang-500.2.75) (based on LLVM 3.3svn)". I see no reason it would not work with your toolchain as well.
Please make an alias:
using AdressBookMap = map<string, AddressBook, function<bool(const string&, const string&)>>;
Then use it:
void foo(AddressBookMap& myAddressBook)
{
// ...
}
int main(int argc, char* argv[])
{
auto myComparator = [] (...) { ... };
AddressBookMap myAddressBook(myComparator);
foo(myAddressBook);
return 0;
}
As Whoz said, lambdas are not std::function; the latter can be implicitly constructed from the former, but they don't have the same type. This means a std::map parametrized by one is completely unrelated to a std::map parametrized by the other.

Pointer to method

Anyone knows how to compile this example code under msvc2010 ? (supposedly compiles under GCC)
class cmdLine;
struct cmdList
{
const char *c;
const char *s;
const char *h;
void (cmdLine::*cmdFuncPtr)();
};
class cmdLine
{
public:
cmdLine();
static cmdList myCmdList[];
void test();
};
cmdLine::cmdLine()
{
}
void cmdLine::test()
{
}
cmdList cmdLine::myCmdList[] =
{
{"xxx", "yyy", "zzzzz", &cmdLine::test},
{"aaa", "bbb", "ccc", 0}
};
int _tmain(int argc, _TCHAR* argv[])
{
cmdLine c;
(c.myCmdList[0].*cmdFuncPtr) (); //error (why?)
}
I get error C2065: 'cmdFuncPtr' : undeclared identifier and dont know whats wrong ?
Use this syntax
(c.*c.myCmdList[0].cmdFuncPtr) ();
As cmdFuncPtr is a pointer to a method of cmdLine, it needs an instance of the class to be invoked on, which is c. At the same time, cmdFuncPtr is a member of cmdList, so it needs an instance of the class where it is stored, which is c.myCmdList[0]. That's why c shall be used twice in the expression.
The expression presented by OP parses as: "Invoke a method on an instance of a class in c.myCmdList[0] through a method pointer stored in a standalone variable cmdFuncPtr". Such variable doesn't exist, that's what the compiler complains about.