File pointer does not works when moved to a class? - c++

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.

Related

string to char* conversion

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());
}

Using Boost Python for C++ class which takes user input

I have a C++ class which takes user input in the constructor and then writes that (and other stuff) onto a file. It works perfectly fine on C++ (both on MSVC and GCC) and now I would like to use this class in my Python projects. My files are:
foo.h
#include <iostream>
#include <fstream>
#include <stdio.h>
class Foo
{
public:
explicit Foo(const std::string file_name, const std::string other_input);
virtual ~Foo();
void Write(const std::string random_text);
private:
std::ofstream output_file;
char buffer[200];
std::string random_string;
};
foo.cpp
#include <Python.h>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
// Constructor
Foo::Foo(const std::string file_name, const std::string other_input)
{
std::ifstream file_exists(file_name)
if(file_exists.good())
output_file.open(file_name, std::ios_base::app);
else
output_file.open(file_name);
random_string = other_input;
}
// Destructor
Foo::~Foo()
{
output_file.close();
}
// Write to a file
void Foo::Write(const std::string random_text)
{
sprintf( buffer, "%s", random_string );
output_file << buffer << ";\n";
}
// Boost.Python wrapper
BOOST_PYTHON_MODULE(foo)
{
boost::python::class_<Foo>("Foo", boost::python::init<>())
.def("Write", &Foo::Write)
;
}
When I try to compile this on Visual Studio or GCC, I am getting the following error:
'std::basic_ofstream<_Elem,_Traits>::basic_ofstream' : cannot access private member declared in class 'std::basic_ofstream<_Elem,_Traits>'
I am totally confused regarding why this is the case. I have tried another variant of the wrapper, namely:
// Boost.Python wrapper
BOOST_PYTHON_MODULE(foo)
{
boost::python::class_<Foo, boost::noncopyable>("Foo", boost::python::init<>())
.def("Write", &Foo::Write)
;
}
And here I get the error:
'Foo' : no appropriate default constructor available
Any ideas to get this to heel would be highly appreciated!
Thanks in advance..
One apparent mistake in your code is that Foo's constructor takes two parameters that you have not included in the wrapper:
// Boost.Python wrapper
BOOST_PYTHON_MODULE(foo)
{
boost::python::class_<Foo, boost::noncopyable>("Foo",
boost::python::init<const std::string, const std::string>())
.def("Write", &Foo::Write)
;
}
This explains the second error and this version (with noncopyable) should now compile fine.

mem_fun_ref: unresolved overloaded function type

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));

error C2064: term does not evaluate to a function taking 1 arguments

class Student {
// ...
bool Graduate() { return m_bGraduate; }
// ...
};
class School {
vector<Student*> m_vecStudents;
void DelAndNullify(Student* &pStd);
void Fun1();
};
void School::DelAndNullify(Student* &pStd)
{
if ( (pStd != NULL) && (pStd->Graduate()) )
{
delete pStd;
pStd = NULL;
}
}
void School::Fun1()
{
for_each(m_vecStudents.begin(), m_vecStudents.end(), mem_fun(&School::DelAndNullify));
}
Error 1 error C2064: term does not evaluate to a function taking 1 arguments C:\Program Files\Microsoft Visual Studio 10.0\VC\include\algorithm 22 1 Simulation
Why do I get this error?
updated
change Student to pStd
updated // algorithm file
template<class _InIt, class _Fn1> inline
_Fn1 _For_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{
// perform function for each element
for (; _First != _Last; ++_First)
_Func(*_First); // <<<<<<<< this line!
return (_Func);
}
BTW, if I define the DelAndNullify as static then the following line passes the compiler
for_each(m_vecStudents.begin(), m_vecStudents.end(), ptr_fun(&School::DelAndNullify));
Updated 05/09/2012
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <iostream>
#include <iomanip>
#include <functional>
#include <boost/bind.hpp>
class Student {
public:
Student(int id, bool bGraduate) : m_iID(id), m_bGraduate(bGraduate) {}
bool Graduate() const { return m_bGraduate; }
private:
int m_iID;
bool m_bGraduate;
};
class School {
public:
School(int numStudent)
{
for (int i=0; i<numStudent; ++i)
{
m_vecStudents.push_back(new Student(i+1, false));
}
}
~School()
{
// deallocate the allocated student resource to prevent memory leak!
}
void DelAndNullify(Student* &pStd);
void Fun1();
private:
std::vector<Student*> m_vecStudents;
};
void School::DelAndNullify(Student* &pStd)
{
if ( (pStd != NULL) && (!pStd->Graduate()) )
{
delete pStd;
pStd = NULL;
}
}
void School::Fun1()
{ // http://stackoverflow.com/questions/6065041/error-c2064-term-does-not-evaluate-to-a-function-taking-1-arguments
std::for_each(m_vecStudents.begin(), m_vecStudents.end(), std::bind1st(std::mem_fun(&School::DelAndNullify), this));
//boost::bind(&School::DelAndNullify, this, _1);
}
int main(int /*argc*/, char* /*argv*/[])
{
School school(10);
school.Fun1();
return 0;
}
Error 1 error C2535: 'void std::binder1st<_Fn2>::operator ()(Student
*&) const' : member function already defined or declared c:\Program Files\Microsoft Visual Studio 10.0\VC\include\xfunctional 299
std::mem_fun(&School::DelAndNullify) returns a binary functor that takes a School* and a Student*, but std::for_each expects a unary functor taking only a Student*. Use Boost.Bind instead:
std::for_each(
m_vecStudents.begin(),
m_vecStudents.end(),
boost::bind(&School::DelAndNullify, this, _1)
);
If you have a sufficiently recent compiler then you can use std::bind or std::tr1::bind instead of the Boost library; or, if you're using a compiler with C++11 lambda support then you can do the following instead of using any bind:
std::for_each(
m_vecStudents.begin(),
m_vecStudents.end(),
[this](Student*& s){ DelAndNullify(s); }
);
Looks like mem_fun turns your member function into a "static" function, which takes an object as its first parameter, like:
static void DelAndNullfify(Student *pStudent);
But you already have a parameter in the pre-mem_fun'd function, so you end up with:
static void DelAndNullfify(School *pSchool, Student* &prStudent);
That's one parameter too much.
this
mem_fun(&School::DelAndNullify)
returns a binary function, expecting a School* and a Student*.
Use
bind1st(mem_fun(&School::DelAndNullify), this)
instead.

Term not evaluated to a function in C++

I have following code, which i taken from Boost and simplified for my project. Please accept my aplogies for pasting complete code, i done it so that it will be easy to answer my question. While compiling following code in VS 2008 i am getting followoing error.
error C2064: term does not evaluate to a function taking 3 arguments
I am expecting addOptions retruns OptionsInit object which call function operator with three arguments but that is not happening, can any one please find bug. Thanks in advance.
namespace MyInfrastructure
{
namespace Internal
{
class OptionDescrp;
class OptionsInit;
}
class OptionsCollection
{
public:
OptionsCollection(std::string optCollName);
Internal::OptionsInit addOptions();
private:
// avoid copying and assignment.
// Prohibit copy
OptionsCollection( const OptionsCollection& );
OptionsCollection& operator = (const OptionsCollection& );
void add(Internal::OptionDescrp* desc) {m_options.push_back(desc);}
std::vector<Internal::OptionDescrp* > m_options;
std::string m_optCollName;
friend class Internal::OptionsInit;
};
}
////////////
#include <string>
#include <vector>
#include <assert.h>
#include "PrgmOptions.h"
namespace MyInfrastructure
{
namespace Internal
{
class OptionDescrp
{
public:
OptionDescrp(std::string pcOptname, std::string description, bool isOptValueReq);
virtual ~OptionDescrp(){ };
private:
std::string m_shortName; // option short name.
std::string m_longName; // option long name.
std::string m_description;// option description.
};
class OptionsInit
{
public:
OptionsInit(OptionsCollection* coll){ owner = coll; }
OptionsInit& operator()(std::string name, std::string description, bool isOptValReq);
private:
OptionsCollection* owner;
};
}
/////
namespace MyInfrastructure
{
OptionsCollection::OptionsCollection(std::string optCollName) : m_optCollName(optCollName) {}
Internal::OptionsInit OptionsCollection::addOptions()
{
return Internal::OptionsInit(this);
}
}
namespace MyInfrastructure
{
namespace Internal
{
// Class Options description definitions.
OptionDescrp::OptionDescrp(std::string pcOptname, std::string description, bool isOptValueReq)
: m_description(description)
{
std::string name(pcOptname);
std::string::size_type n = name.find(',');
if (n != std::string::npos)
{
assert(n == name.size()-2);
m_longName = name.substr(0, n);
m_shortName = '-' + name.substr(n+1,1);
}
else
{
m_longName = name;
}
}
// Class Options Init definitions.
OptionsInit& OptionsInit::operator()(std::string name, std::string description, bool isOptValReq)
{
OptionDescrp* opt = new OptionDescrp(name, description, isOptValReq);
owner->add(opt);
return *this;
}
}
}
//////
int main(void)
{
MyInfrastructure::OptionsCollection desc("myoptions");
**desc.addOptions()("help", "produce help message", false); // error is thrown here**
return 0;
}
The example code in the question compiles without errors with Visual 2008, gcc, Visual 2003 when we copy all in a single file.
You have error C2064, it is probably because you either have a #define or another definition somewhere in other headers that you did not include in your sample, or that somehow you are not compiling exactly the sample code.
Try to copy all the sample code in a single file and compile that.
Interesting code: OptionsInit returned by addOptions() is a temporary. You are then calling a non-const method on it, which is allowed, but it returns a non-const reference to itself which is also allowed because it's a non-const method. But that means essentially you "backdoor" binding a non-const reference to a temporary...
I assume the two asterisks before desc.addOptions are not really in your code as there is no operator* overloaded here.
Perhaps if you make operator() const and return const-reference it will work.
problem is with VS2008. I compiled with VS2010, it compiled fine. Thanks all for the inputs.