Calling a method, and passing in a pointer to class - c++

I'm trying to call a method to add to an object to a vector within another object. I'm getting the error;
'': Illegal use of this type as an expression
Within my program I declare an object to store my node in the main;
accountStream *accountStore = new accountStream;
Then call the function;
new_account(&accountStore);
The new_account function is as;
void new_account(accountStream &accountStorage)
{
newAccount *account = new newAccount;
(&accountStorage)->pushToStore(account);
}
The account stream class has a vector that receives it, but there is where my error is;
class accountStream
{
public:
accountStream();
~accountStream();
template <class account>
void pushToStore(account);
private:
std::vector <newAccount*> accountStore;
};
template<class account>
inline void accountStream::pushToStore(account)
{
accountStore.push_back(account);
}
The error is on the second last line;
accountStore.push_back(account);
I've got a feeling it's something to do with the way I'm passing the object into the method, but after messing around for a while I haven't been able to pinpoint where exactly I've gone wrong.

2 problems:
new_account(&accountStore); is wrong, use new_account(*accountStore); to match the argument type.
accountStore.push_back(account); is wrong. account is type not object. Add some argument to the function.

Several issues:
You must specify the variable name here (and not only the type):
template<class account>
inline void accountStream::pushToStore(account c)
{
accountStore.push_back(c);
}
You must receive a pointer (not a reference to a pointer) here
void new_account(accountStream *accountStorage)
{
newAccount *account = new newAccount;
accountStorage->pushToStore(account);
}
You must call the function with a pointer as a parameter:
new_account(accountStore);
Alternatively, you can declare the variable (not a pointer to):
accountStream accountStore;
call the function:
new_account(accountStore);
and receive a reference:
void new_account(accountStream &accountStorage)
{
newAccount *account = new newAccount;
accountStorage.pushToStore(account);
}

As answered here already, you need to use *accountStore and not &accountStore because the function takes a reference and not a pointer to a pointer (which is what you get from using & operator on a pointer).
the second problem is here:
template<class account>
inline void accountStream::pushToStore(account)
{
accountStore.push_back(account);
}
you are declaring the function templated on the 'account' therefore account is a type, and what you are trying to do in the next line is push_back a type and not an object.
the correct code would be:
template<class account>
inline void accountStream::pushToStore(account acct)
{
accountStore.push_back(acct);
}
because account is the type while acct is an instance of the type account.

Related

Is it possible to access the arguments from an std::bind object?

Please consider the following scenario.
A hypothetical pop-up menu class that displays some actions, and when one of them is selected it will call the passed in action which is in form of an std::function:
PopupMenu::PopupMenu(std::function<void(RowItem*)> editRowFunction, RowItem *item)
: _editRowFunction(editRowFunction)
, _item(item) {
}
Then at some point it might call execute:
PopupMenu::execute(} {
_editRowFunction(_item);
}
Then I have this other class that's a UI object:
class EditorWidget {
void editRow(RowItem *row) {
//edit the row
}
}
And here's how I am using all of them:
int main() {
auto item = new RowItem();
auto editorWidget = new EditorWidget();
PopupMenu menu(std::bind(&EditorWidget::editRow, editorWidget, item), item);
menu.execute();
return 0;
}
Everything works. My question is the following:
If I am already passing the argument item in std::bind, why do I have to pass it again as a second parameter in order to be able to call the bound function with that argument? If I don't, and try to call the function just by itself from PopupMenu::execute(), I get a compiler error.
The other way around it is to make the constructor of PopupMenu like this:
PopupMenu::PopupMenu(std::function<void()> editRowFunction)
: _editRowFunction(editRowFunction) {}
And if I do it that way then I call it this way:
PopupMenu::execute() {
_editRowFunction();
}
What I don't like about this method is that I can pretty much pass any bound function in the PopupMenu constructor and it will be called. But that's not what I want, I want to enforce only a function with a specific signature.
I can also pass a lambda, yes. But let's try to solve it without lambdas.
Thank you all in advance for your help.
std::bind(&EditorWidget::editRow, editorWidget, item)
std::bind here is creating a functional object that takes a pointer to a member function EditorWidget::editRow, bound to an object editorWidget, using the parameter item. What you've done is actually fix the parameter to the function EditorWidget::editRow with the parameter item. So effectively you've created a function object that takes no argument (since you've fixed it), and returns void.
There's actually no need for the constructor of PopupMenu to have a second parameter of type RowItem*. You could change the constructor like so:
PopupMenu::PopupMenu(std::function<void()> editRowFunction)
: _editRowFunction(editRowFunction)
{
}
and then call your function object like this:
PopupMenu::execute(} {
_editRowFunction();
}
In your current code the parameter _item is not being used by the function object you pass into the constructor PopupMenu. It satisfies the compiler since _editRowFunction is of type std::function<void(RowItem*)>.
Here's a simple example to illustrate to the point:
#include <iostream>
#include <functional>
struct callable
{
callable(std::function<void(std::string)> fn) : mFn(fn)
{}
std::function<void(std::string)> mFn;
void Run() { mFn("world"); }
};
struct Foo {
void print(std::string msg)
{
std::cout << msg << '\n';
}
};
int main()
{
Foo f;
auto fn = std::bind(&Foo::print, &f, "hello");
fn();
callable c(fn);
c.Run(); //expecting "world" to be printed
}
You might expect the output to be:
hello
world
but actually it's:
hello
hello
Live demo.
What I could do is change the definition of the function object like this:
auto fn = std::bind(&Foo::print, &f, std::placeholders::_1); //uses a placeholder
and I get the expected output. You could do something similar without having to make many changes to your current implementation.

C++ calling constructor to initialize an object yields errors

What's wrong with this:
struct FileListItem {
string sOriginalFn;
time_t ttTimeTaken;
FileListItem(){}
FileListItem(string _sOriginalFn, time_t _ttTimeTaken) :
sOriginalFn (_sOriginalFn), ttTimeTaken (_ttTimeTaken) { }
};
struct FileList : vector<FileListItem> {
int iCurItm;
FileList() : vector(), iCurItm(-1) {};
void Add(string _sOriginalFn, time_t _ttTimeTaken) {
push_back(FileListItem(_sOriginalFn, _ttTimeTaken));
}
}
I get a run-time "read access violation" the first time Add is called.
I then try:
struct FileList : vector<FileListItem> {
int iCurItm;
FileList() : vector(), iCurItm(-1) {};
FileListItem Itm; // <--- new member
void Add(string _sOriginalFn, time_t _ttTimeTaken) {
Itm(_sOriginalFn, _ttTimeTaken); // <--- E0980 pointing to "Itm"
push_back(Itm);
}
}
and get a compile time error:
E0980 - call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type.
I must have forgotten or missed something since I stopped programming 30 years ago, when Borland C++ was IT...
In the line
Itm(_sOriginalFn, _ttTimeTaken);
You are not calling the constructor for your object. Instead, the compiler interprets this as a function call on the functor Itm. Therefore, it tries to find a valid operator() for the given arguments, to no-avail.
Do not use constructor member initializer list syntax elsewhere than... Constructor member initializer list. Instead, what you have to do here is to assign a new object to your member.
Then, you don't want, ever to inherit from std containers. Their destructor is not virtual so you are exposing yourself to a realm of suffering...
Use composition or type aliasing instead:
struct FileList {
std::vector<FileListItem> flist;
int curItem;
FileList() : flist(), curItem(-1) {}
void Add(string const& _sOriginalFn, time_t _ttTimeTaken) {
// No need to construct the object before, let vector handle it
flist.emplace_back(_sOriginalFn, _ttTimeTaken);
};
As for the read access violation, from the code I see, nothing explains it. Could it be some access related to curItem somewhere in your code that isn't displayed here?

c++ save class templated function pointer inside map

I'm having a small problem which I can't wrap my head around.
I have a function that looks like this:
template <typename T>
std::unique_ptr<Environment>& CreateEnvironment(sf::Vector2f& _position, bool _addToStatic = false);
This is my function pointer typedef
typedef std::unique_ptr<Environment>& (WorldEditor::*CreateEnvironmentPtr)(sf::Vector2f&, bool);
std::map<std::string,CreateEnvironmentPtr> listEnv;
And I'm trying to simply do this:
listEnv["test"] = &CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
And i get the following error:
error C2440: '=' : cannot convert from 'std::unique_ptr<_Ty> *' to
'std::unique_ptr<_Ty> &(__thiscall WorldEditor::* )(sf::Vector2f
&,bool)'
I understand what the error is saying, but I don't know how to solve it. Also why does it even care about the return type when I'm pointing to the address of the function?
Best regards
nilo
problems such as these are often much better solved with std::function
std::map<std::string, std::function<void()> listEnv;
listEnv.emplace("test", [] {
CreateEnvironment<Coin>(sf::Vector2f(200,200), false);
});
to call:
listEnv.at("test")->second();
Based on your post I am not sure if you are attempting to create the member function pointer and map inside the CreateEnvironment class or outside of it, so I'll solve what I think is the more difficult problem of pointer to a separate object's member function.
I simplified your classes like so:
Environment
struct Environment
{
int i = 1;
};
Coin
struct Coin
{
int k = 0;
};
WorldEditor
struct WorldEditor
{
template <typename T>
std::unique_ptr<Environment> CreateEnvironment(int& _j, bool _addToStatic = false)
{
return std::make_unique<Environment>();
}
};
Solution: Map an object's member fn pointer, and then call it later
(I will be using C++11/14 syntax in my answer)
//declare a pointer to member function in WorldEditor
using CreateEnvironmentPtr = std::unique_ptr<Environment> (WorldEditor::*)(int&, bool);
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to the CreateEnvironment<Coin> function
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = &WorldEditor::CreateEnvironment<Coin>;
// call the member function pointer using the instance I created, as well as
// the mapped function
(myWorldEditor.*listEnv["test"])(myInt, false);
// (printing member value to cout to show it worked)
std::cout << (myWorldEditor.*listEnv["test"])(myInt, false)->i << std::endl; // prints 1
Live Demo
Solution 2: use std::bind and std::function
Perhaps we already know the parameters to the member function call at the time we create the entry for map. Using std::bind with a std::function will help us achieve that (Similar to Richard Hodges' solution):
// now our "function pointer" is really just a std::function that takes no arguments
using CreateEnvironmentPtr = std::function<std::unique_ptr<Environment>(void)>;
//declare an object of type WorldEditor, because member function pointers need a "this" pointer
WorldEditor myWorldEditor;
int myInt = 42;
//map a string to that function pointer
//ensure it gets called with the right args
// by using std::bind (which will also make the arg list appear the be void at call time)
// note that std::bind needs an instance of the class immediately after
// listing the function it should be binding
// only afterwards will we then pass the int& and bool
std::map<std::string, CreateEnvironmentPtr> listEnv;
listEnv["test"] = std::bind(&WorldEditor::CreateEnvironment<Coin>, &myWorldEditor, myInt, false);
// the mapped function
listEnv["test"]()->i;
// (printing resulting unique_ptr<Environment>'s member to cout to show it worked)
std::cout << listEnv["test"]()->i << std::endl; // prints 1
Live Demo 2

Accessing member function from member function array

I have grouped several member functions into an array. How do I access a function from the array? I am getting 'error C2064: term does not evaluate to a function taking 0 arguments.' See below.
class A
{
public:
//Constructor
A()
{
//Fill function array
ClipFunction[0] = &A::ClipTop;
ClipFunction[1] = &A::ClipBottom;
ClipFunction[2] = &A::ClipLeft;
ClipFunction[3] = &A::ClipRight;
}
//Declare array
typedef void (A::*ClipFunction_ptr) ();
ClipFunction_ptr ClipFunction[4];
//Clipping functions
void ClipTop();
void ClipBottom();
void ClipLeft();
void ClipRight();
//Start clipping process
void StartClip();
};
//Define clipping functions
void A::ClipTop() {}
void A::ClipBottom() {}
void A::ClipLeft() {}
void A::ClipRight() {}
//Define A::StartClip()
void A::StartClip()
{
//Run through all functions in the array
for (unsigned int i = 0; i < 4; i++)
{
ClipFunction[i](); //ERROR. How do I access ClipFunction[i] ???
}
}
You need to dereference the function like this:
this->(*ClipFunction[i])();
What you're missing is the this or rather the compiler is complaining that it doesn't have the first parameter (the instance of the object invoking the member function) to pass it to the function.
To the compiler the member function:
void A::ClipFunction()
{
}
translates to something like:
void ClipFunction(A* this)
{
}
Hence the error complaining that the function is not one that takes zero arguments.
I think the problem is that you need use "this" explicitly as in http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/topic/com.ibm.xlcpp8l.doc/language/ref/cplr034.htm .
So in your case, you should use
(this ->* ClipFunction[i]) ();
instead of
ClipFunction[i]();
PS
When I reply this post, I didn't see Vite Falcon's answer. Basically we are saying the same thing but I don't think his code " this->(*ClipFunction[i])()" will compile because GCC gives errors on my machine. "(this->*ClipFunction[i])()" is the correct form.
I don't think you want the scope resolution operator :: in your typedef. Instead try putting
typedef void (*ClipFunction_ptr) ();

reference error

I have a header in which I declare a function. Then I create the function and try to use it but i get an error. It is by reference but I don't know why it is not working.
struct.h
#ifndef LISTSTRUC_H_
#define LISTSTRUC_H_
template <class T> struct Array{
int days;
T * M;
Array( int size ) : days(size), M(new T[size])
{
}
~Array()
{
delete[] M;
}
};
void currentDay();
template <class Expe>
void dummyData(Array<Expe> &);
#endif /* LISTSTRUC_H_ */
struct.cpp
void dummyData(Array <Expe> &A){
for(int i=0; i<31; i++){
A.M[i].Expe::setObj((i*3),(i*1),(i*6),(i*2),(i*4),(i*5));
}
}
M.cpp(Main cpp)
int main(){
//Main function of the program. no pre/ post condition.
Array <Expe> A(31); // Work space
Array <Expe> B(31); // Backup space
dummyData(&A); // error
}
ERROR:
..\M.cpp:22:14: error: no matching function for call to 'dummyData(Array<Expe>*)'
dummyData(&A);
should be:
dummyData(A);
Rationale:
Your function takes a reference not a pointer, &A means you are passing address of the type which can only be received in by a pointer to that type and you don't have that overloaded version of the function, hence the error.
If passing object by reference, don't pass its address, like you did here:
dummyData(&A);
Just pass the object itself (as reference is its alias):
dummyData(A);
You shouldn't put reference & to pass a variable by reference, simply pass it.
dummyData(A);
Passing by reference means that you are not copying the object, instead you are using the object itself and, if passed as variable (not const) changes will affect it.
dummyData(&A);
should be
dummyData(A);
The & operator in this context is taking the address of A which is a pointer. To pass a reference you just use the actual variable name.