I am in a code base where there are lots of function calls to functions that take a pointer as an argument. However, the function call passes a "string" object as if it's pointer. The following code is shown to give you an idea.
#include <vector>
#include <unordered_map>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <string>
using namespace std;
void dum(char *s) {
printf("%s\n", s);
}
operator char* (string s) {
return s.c_str();
}
int main(int argc,char *argv[]) {
string st("Hello world");
dum(st);
return 0;
}
I am not allowed to change the syntax for all these functions or function calls. One possible solution I came up is to add a operator overload, but unfortunately it doesn't work, here is the error from g++ (ver 4.7.3), command line: g++ -std=c++11 te2.cc
error: ‘operator char*(std::string)’ must be a nonstatic member function
Any ideas? Thanks.
UPDATE1
#ferruccio's answer reminded me to mention that there are function calls like
dum(dum2());
where dum2() is a function is like:
string dum2() {
string s;
//.....
return s;
}
So the wrapper like the following doesn't work (), compiler gives error no matching function for call to ‘dum(std::string)’
void dum(string &s) {
dum(s.c_str());
}
operator char* (string s) {
return s.c_str();
}
This is broken (if it was allowed). When this function returns, s no longer exists. So a pointer to its contents is of no use.
You could add a simple function overload for each function that takes a char*. e.g.
void dum(const string& s) {
dum(s.c_str());
}
Related
I have two classes: "Station" which has method getName() returning string and "Profit" which has the overloaded method sellAt(string stName), sellAt(Station st). To avoid duplicate code I call sellAt(string stName) in sellAt(string stName), however in some cases (see code example below) compiler gives an error: "no instance of overloaded function "Profit::SellAt" matches the argument list. Argument types are: (std::string)". Is it a bug or I miss something?
Station.h
#pragma once
#include <string>
using namespace std;
class Station
{
private:
string sName;
public:
Station(string name);
string getName();
};
Station.cpp
#include "Station.h"
Station::Station(string name)
:sName(name)
{}
string Station::getName()
{
return sName;
}
Profit.h
#pragma once
#include "Station.h"
#include <string>
class Profit
{
public:
double SellAt(string& stName);
double SellAt(Station& st);
};
Profit.cpp
#include "Profit.h"
double Profit::SellAt(const string& stName)
{
// do stuff
}
// Works as expected
double Profit::SellAt(Station& st)
{
string stName = st.getName();
return SellAt(stName);
}
// Compile error
double Profit::SellAt(Station& st)
{
return SellAt(st.getName());
}
// Compile error
double Profit::SellAt(Station& st)
{
double result = SellAt(st.getName());
return result;
}
Yksisarvinen answered in the comment below the original question:
st.getName() is a temporary. You cannot bind non-const reference to a temporary. I suppose you shouldn't want to modify stName in Profit::SellAt(), so change the type of argument to const std::string&.
Thanks for the help!
So I found this solution to call a python script and it works in Microsoft Visual Studio Professional 2019 Version 16.6.2. I moved the three methods into a separate class and it no longer works. I thought I could figure it out but have just been beating myself up so I am here asking for help from readers who are much more knowledgeable than myself. The working code follows.
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
#include <iostream>
#include <string>
void close_file(std::FILE* fp) {
std::fclose(fp);
}
std::string exec_python(const char* scriptCommand) {
std::array<char, 256> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&close_file)> _pipe(_popen(scriptCommand, "r"), close_file);
if (!_pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), static_cast<int>(buffer.size()), _pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
std::string call_script(std::string ScriptLoc, std::string Script_Parameters) {
std::string ScriptInput = ScriptLoc + " " + Script_Parameters;
std::string result = exec_python(ScriptInput.c_str());
return result;
}
int main()
{
std::string LOne = "python.exe \"C:\\Users\\.....\\source\\repos\\PyApplication1\\PyApplication1.py\"";
std::string LTwo = " Message";
//system(LTwo.c_str());
std::string oRez=call_script(LOne,LTwo);
std::cout <<"Results:"+oRez << std::endl;
}
The separate class that will not compile and related error messages follow. first is the header file, iTool.h.
#pragma once
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
#include <iostream>
#include <string>
class iTool {
public:
void close_file(std::FILE* fp);
std::string exec_python(const char* scriptCommand);
std::string call_script(std::string ScriptLoc, std::string Script_Parameters);
iTool();
};
The second is the iTool.cpp.
#include "iTool.h"
void iTool::close_file(std::FILE* fp) {
std::fclose(fp);
}
std::string iTool::exec_python(const char* scriptCommand) {
std::array<char, 256> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&close_file)> _pipe(_popen(scriptCommand, "r"), close_file);
if (!_pipe) {
//throw std::runtime_error("_popen() failed!");
} else { throw std::runtime_error("_popen() failed!"); }
while (fgets(buffer.data(), static_cast<int>(buffer.size()), _pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
std::string iTool::call_script(std::string ScriptLoc, std::string Script_Parameters) {
std::string ScriptInput = ScriptLoc + " " + Script_Parameters;
std::string result = exec_python(ScriptInput.c_str());
return result;
}
iTool::iTool() = default;
The error messages.:
Severity Code Description Project File Line Suppression State
Error C2088 '!': illegal for class TestAppliance1 C:\Users\....\source\repos\TestAppliance1\iTool.cpp 11
Error C2276 '&': illegal operation on bound member function expression TestAppliance1 C:\Users\...\source\repos\TestAppliance1\iTool.cpp 10
Error C2514 'std::unique_ptr': class template cannot be constructed TestAppliance1 C:\Users\...\source\repos\TestAppliance1\iTool.cpp 10
Error C2660 'fgets': function does not take 2 arguments TestAppliance1 C:\Users\...\source\repos\TestAppliance1\iTool.cpp 14
Error C2662 '_Get_deleter_pointer_type<_Ty,remove_reference<_Ty1>::type,void>::type std::unique_ptr<_Ty,_Dx>::get(void) noexcept const': cannot convert 'this' pointer from 'std::unique_ptr' to 'const std::unique_ptr<_Ty,_Dx> &' TestAppliance1 C:\Users\...\source\repos\TestAppliance1\iTool.cpp 14
Thanks for your help!
You tripped over a non-static member function having a hidden this parameter and not matching the prototype expected for a deleter function.
Instead of void (*)(std::File*), the proposed deleter looks something like void (iTool::*(std::File*)
You can solve the problem by wrapping the function call with a lamda expression that captures this, but since close_file doesn't use this (something wrong with that--fp should probably be a member variable--that is outside the scope of this question), lets go with making it a static member function. The asker can clean up the ideological problems later.
In the iTool class definition,
void close_file(std::FILE* fp);
becomes
static void close_file(std::FILE* fp);
After you create a class you must create an instance of that class in the main function before you can use it:
iTool tool()
Inside you mean function.....
Also one word of caution for you my friend, if you do not know what:
iTool::iTool() = default;
Sets your variables to please do not use it...... You can always define those variables by yourself in your private part, if you know what the default does, by all means go ahead.
Let's say I have a String class that can be constructed with a char array pointer. Is there any crazy way, through some magical operator overload, free function, or preprocessor macro to make Python-like syntax work, autocasting a char array literal to a String? To make this compile:
String a = "Foo".substr(1);
I suppose a wild pre-compile sed statement would do it, but something within the abilities of clang would be preferred.
For C++11 and beyond
#include <iostream>
#include <string>
int main() {
using namespace std::string_literals;
auto a = "foo"s.substr(1);
}
If you wanted to write this for your own String class then the way to get the same behavior would be to roll your own user defined string literal, and then do the same
#include <cstddef>
class Str {
public:
explicit Str(const char*) {}
Str substr(int) { return *this; }
};
Str operator"" _s (const char* input, std::size_t) {
return Str{input};
}
int main() {
auto s = "something"_s.substr(1);
}
I need to have struct member being a regular function pointer (not a class member function pointer). Not sure why the compile error. I am running g++ 4.8.4 on Ubuntu 14.04. Thanks.
$ g++ te5.cc
te5.cc: In function ‘int main(int, char**)’:
te5.cc:18:9: error: invalid use of member function (did you forget the ‘()’ ?)
t.func = dum;
^
te5.cc:19:6: error: ‘func’ was not declared in this scope
(t.*func)();
Code snippet
#include <stdio.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void pfpv(void *obj);
typedef struct {
pfpv func;
void *obj;
} strTimer;
void dum(void* p) {
printf("in dum()\n");
}
int main (int argc, char *argv[]) {
strTimer t;
t.func = dum;
(t.*func)();
return 0;
}
This can be solved by making pfpv a function pointer instead of a function.
#include <stdio.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void (*pfpv)(void *obj);
typedef struct {
pfpv func;
void *obj;
} strTimer;
void dum(void* p) {
printf("in dum()\n");
}
int main (int argc, char *argv[]) {
strTimer t;
t.func = dum;
t.func(0);
return 0;
}
There are several mistakes here.
typedef void (*pfpv)(void *obj); … you'd left out the first *, so pfpv was just a function type, not a function pointer type.
(t.func)(); You'd used pointer-to-member-function call syntax, but your t.func is just a normal function pointer, so use . not .*.
Furthermore, you're not passing any arguments to a function that expects a void*. We can pass nullptr, for now.
Here it is compiling, with those fixes in place.
This whole debacle could have been avoided if you'd used the far simpler std::function:
#include <iostream>
#include <functional>
struct strTimer
{
std::function<void(void*)> func;
void* obj;
};
void dum(void* p)
{
std::cout << "in dum()\n";
}
int main()
{
strTimer t;
t.func = &dum;
(t.func)(nullptr);
}
Live demo
No need for that antiquated C cruft!
Presumably, passing void* as argument is also designed to satisfy some primordial C idiom, perhaps by passing in &t (instead of nullptr) to simulate member functions. You should consider using lambda functions and other modern language features; your program will be much easier to write, maintain and debug.
The problem is your function pointer typedef (it doesn't specify a function pointer). Change it like so:
typedef void (*pfpv)(void *obj);
Also the call of the function pointer is wrong:
(t.func)(&t);
Live Demo
The following code won't compile because of "error: no matching function for call to ‘mem_fun_ref()’" (gcc version 4.4.6).
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
class toto
{
char v[10];
public:
toto(char* t) { memcpy(v, t, 9); }
bool test(const char* var) const { return !strncmp(var, v, 9); }
bool test(const string& var) const { return test(var.c_str()); }
};
int main()
{
vector<toto> t;
t.push_back("1");
t.push_back("2");
string name("2");
vector<toto>::iterator it = remove_if(t.begin(), t.end(),
bind2nd(mem_fun_ref(&toto::test), name)); // <= error
t.erase(it, t.end());
return 0;
}
I found a workaround: creating a
bool testZ(const string& var) const { return testZ(var); }
But I can't seem to find the correct template parameters, if that's even possible, to give to mem_fun_ref (or bind2nd?) to make it compile without my workaround.
Is there anyway to achieve this without my workaround, or is the workaround the "preferred" method?
You should be able to cast it according to C++ overloaded method pointer:
bind2nd(mem_fun_ref((bool (toto::*)(const string&) const) &toto::test), name));