C++; class method pointer; lambda; passing lambda as member function pointer; - c++

Here is what I try to achieve:
class MyClass
{
public:
using Callback = void(MyClass::*)(uint8_t idx);
void forEach(Callback callback);
private:
int m_buf[64];
int m_x;
int m_y;
MyObject m_object;
}
void MyClass::forEach(Callback callback)
{
size_t s = m_object.size();
for(size_t i = 0; i < s; i++)
callback(i);
}
void MyClass::f1()
{
forEach([this](uint8_t idx)
{
m_buf[idx]++;
});
}
void MyClass::f2()
{
forEach([this](uint8_t idx)
{
m_buf[idx] = m_x + m_y * idx;
});
}
So there are a bunch of ways to modify m_buf[]. In order to avoid copying and pasting 'get size + for loop', I want to add a forEach method and pass lambdas as callbacks.
this is captured to have access to class members.
What is the right way to achieve the same result?
Thanks.
PS: compilation of this example returns error 'cannot convert ::lambda ....'
ANSWER:
With "Passer By" answer, I finished with the code:
// Class declaration in header
using Callback = std::function<void(uint8_t)>;
void forEach(Callback callback);
// forEach() is as above
// forEach() call looks like
forEach([this](uint8_t idx) {
m_buf[idx] = m_x + m_y * idx;
});
Also I found some related questions-anwers which might be useful
Passing lambda as function pointer - "5gon12eder" answer.
C++ lambda with captures as a function pointer

You have mistaken the semantics of a member function pointer
void (MyClass::*)(uint8_t idx)
is a pointer to a member function of MyClass that accepts a uint8_t, it is not anything else. You call it as
MyClass::Callback c = &MyClass::SomeMemberFunction;
MyClass mc;
(mc.*c)(0); // equivalent to...
mc.SomeMemberFunction(0);
Secondly, the purpose of for_each is so that the callable object passed in need not know the internals of the object, as such, you shouldn't pass in an index in the loop.
What you actually want is to pass in a callable object accepting a reference called on each object. This can be done in two ways
template<typename Callable>
void for_each1(Callable&& call)
{
for(size_t i = 0; i < size(); i++)
call(m_buf[i]);
}
#include<functional>
void for_each2(std::function<void (int&)>&& fn)
{
for(size_t i = 0; i < size(); i++)
fn(m_buf[i]);
}
Both can be called with a lambda
MyClass mc;
mc.for_each1([](int& i) { i++; });
mc.for_each2([&mc](int& i) { i += mc.increment(); });
where mc.increment is what that instance wants to be incremented by.

Related

Adapting constructor to factory requirement

I'm deriving a class from a base class outside my control. The class will get created by a factory function pointer I pass in (in a part of the code I also don't control).
In my derived class, I need to pass an additional constructor argument to the factory function.
My first stab was to try to adapt the factory function via a lambda, but that cannot capture the additional argument. Other answers explained why that doesn't work. Next I've tried to augment that with std::function which other answers have led me to believe would work, but I can't figure out the right syntax and have found the examples to be incomprehensible (and not sure I really understand what that is even doing).
What am I doing wrong here? Is there a better way to solve this?
Demonstration code:
#include <functional>
#include <string>
// I have no control over this
struct Base {
Base(int i) {}
};
void UseObject(Base *(*factory)(int i)) {
Base *instance = factory(5);
// Save created instance
}
// I control the rest
struct Derived : public Base {
Derived(const char *s, int i) : Base(i) { /* Store s for later use */ }
static Base *Factory(const char *s, int i) { return new Derived(s, i); }
};
void AddObject(const char *name)
{
// First stab
// UseObject([name] (int i) { return Derived::Factory(name, i); });
// Second stab
std::function<Base *(int i)> foo { [name] (int i) { return Derived::Factory(name, i); } };
UseObject(foo);
}
int main(int ac, char **av)
{
AddObject("some_name");
AddObject("another_name");
return 0;
}
The error I get from g++ (7.4.0) is:
tfunc.cpp: In function ‘void AddObject(const char*)’:
tfunc.cpp:28:18: error: cannot convert ‘std::function<Base*(int)>’ to ‘Base* (*)(int)’ for argument ‘1’ to ‘void UseObject(Base* (*)(int))’
UseObject(foo);
UseObject doesn't allow non capturing lambda or std::function or regular class functor. The only callable it accepts is function pointer (non capturing lambda can convert to).
So you might do:
UseObject([](int i) { return Derived::Factory("some_name", i); });
but not
auto name = "some_name";
UseObject([name] (int i) { return Derived::Factory(name, i); });
Possible (limited) workaround is to use global variable to store state. (So cannot be used concurrently).
void AddObject(const char *name)
{
// global usage as UseObject only accepts pointer function
static const char* instance = nullptr;
instance = name;
UseObject(+[](int i) { return Derived::Factory(instance, i); });
}

std::find return a class that I can't acesses functions

I come from C/C# language and now I'm trying to learn about C++ and his standards functions.
Now, I'm creating a class called IMonsterDead. I will have a std::vector<IMonsterDead*> with N monsters.
Example:
class IMonsterDead {
public:
IMonsterDead(int Id)
{
this->_Id = Id;
}
virtual void OnDead() = 0;
int Id() const {
return _Id;
}
private:
int _Id;
};
One class which implements that class:
class MonsterTest : public IMonsterDead {
public:
MonsterTest(int generId)
: IMonsterDead(generId)
{
}
virtual void OnDead()
{
std::cout << "MonsterTesd died" << std::endl;
}
};
Ok, if I access directly everything works fine. But I'm trying to use std::find.
Full program test:
int main()
{
std::vector<IMonsterDead*> monsters;
for (int i = 0; i < 1000; i++)
{
monsters.emplace_back(new MonsterTest(1000 + i));
}
int id = 1033;
std::vector<IMonsterDead*>::iterator result = std::find(monsters.begin(), monsters.end(), [id]( IMonsterDead const* l) {
return l->Id() == id;
});
if (result == monsters.end())
std::cout << "Not found" << std::endl;
else
{
// Here I want to access OnDead function from result
}
return 0;
}
So I need to access OnDead function from result but I can't. Intellisense doesn't show anything for me. The result exists.
How can I access that function? Have another better way to do that?
You need to use std::find_if() instead of std::find(). std::find() is for finding an element with a specific value, so you have to pass it the actual value to find, not a user_defined predicate. std::find_if() is for finding an element based on a predicate.
Either way, if a match is found, dereferencing the returned iterator will give you a IMonsterDead* pointer (more accurately, it will give you a IMonsterDead*& reference-to-pointer). You need to then dereference that pointer in order to access any members, like OnDead().
You are also leaking memory. You are not delete'ing the objects you new. And when dealing with polymorphic types that get deleted via a pointer to a base class, the base class needs a virtual destructor to ensure all derived destructors get called properly.
With that said, you are clearly using C++11 or later (by the fact that you are using vector::emplace_back()), so you should use C++11 features to help you manage your code better:
You should use std::unique_ptr to wrap your monster objects so you don't need to delete them manually.
You should always use the override keyword when overriding a virtual method, to ensure you override it properly. The compiler can catch more syntax errors when using override than without it.
You should use auto whenever you declare a variable that the compiler can deduce its type for you. Especially useful when dealing with templated code.
Try something more like this:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
class IMonsterDead {
public:
IMonsterDead(int Id)
: m_Id(Id)
{
}
virtual ~IMonsterDead() {}
virtual void OnDead() = 0;
int Id() const {
return m_Id;
}
private:
int m_Id;
};
class MonsterTest : public IMonsterDead {
public:
MonsterTest(int generId)
: IMonsterDead(generId)
{
}
void OnDead() override
{
std::cout << "MonsterTest died" << std::endl;
}
};
int main()
{
std::vector<std::unique_ptr<IMonsterDead>> monsters;
for (int i = 0; i < 1000; i++)
{
// using emplace_back() with a raw pointer risks leaking memory
// if the emplacement fails, so push a fully-constructed
// std::unique_ptr instead, to maintain ownership at all times...
monsters.push_back(std::unique_ptr<IMonsterDead>(new MonsterTest(1000 + i)));
// or:
// std::unique_ptr<IMonsterDead> monster(new MonsterTest(1000 + i));
// monsters.push_back(std::move(monster));
// or, if you are using C++14 or later:
// monsters.push_back(std::make_unique<MonsterTest>(1000 + i));
}
int id = 1033;
auto result = std::find_if(monsters.begin(), monsters.end(),
[id](decltype(monsters)::value_type &l) // or: (decltype(*monsters.begin()) l)
{
return (l->Id() == id);
}
// or, if you are using C++14 or later:
// [id](auto &l) { return (l->Id() == id); }
);
if (result == monsters.end())
std::cout << "Not found" << std::endl;
else
{
auto &monster = *result; // monster is 'std::unique_ptr<IMonsterDead>&'
monster->OnDead();
}
return 0;
}
Iterators are an interesting abstraction, in this case to be reduced to pointers.
Either you receive the pointer to the element or you get an invalid end.
You can use it as a pointer: (*result)->func();
You can also use it to create a new variable:
IMonsterDead &m = **result;
m.func();
This should give the same assembly, both possible.

Move the same unique_ptr into function in a loop

Whats the best way to redesign the following error prone code:
void ClassA::methodA(std::unique_ptr<ClassB::ISomeInterface> obj){
for (int i = 0; i < 10; i++) {
methodB(std::move(obj)); // the obj pointer is undefined on second iteration here after the move
}
}
void ClassA::methodB(std::unique_ptr<ClassB::ISomeInterface> obj){
..........
}
The goal is to pass the same unique_ptr to function multiple times.
If you don't want to transfer ownership just pass the raw pointer or a reference. If the functions are going to store the pointer a shared_ptr would be more appropriate:
void ClassA::methodA(std::unique_ptr<ClassB::ISomeInterface> obj){
for (int i = 0; i < 10; i++) {
methodB(*obj);
}
}
void ClassA::methodB(ClassB::ISomeInterface& obj){
..........
}
Pass it by (optionally const) reference to methodB.
So instead of having
void ClassA::methodB(std::unique_ptr<ClassB::ISomeInterface> obj);
you can have either of the following
void ClassA::methodB(const ClassB::ISomeInterface& obj);
or
void ClassA::methodB(ClassB::ISomeInterface& obj);

c ++ Class Method Pointer as Function Argument

I am trying to create a dynamic function pointer that points to some methods all the methods I want to save on the array return a bool and have an uint32_t parameter. The functions are Service functions. These are intended to be dynamic, so when a class is started, the constructor links the service function from the object to be called from outside the object.
With the code below I am getting the following error:
Build error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
I have no clue what to do to overcome this problem, any idea would be greatly appreciated, thanks!
//File 1
typedef bool (*ServiceFunctionsType)(uint32_t);
//File 2
#include "File1.hpp"
extern uint8_t ServiceFunctions_size;
extern ServiceFunctionsType *ServiceFunctions;
void Service_Functions_Setup();
bool SetPtr(ServiceFunctionsType a);
void ClearPtr(uint8_t id);
//File 3
#include "File1.hpp"
ServiceFunctionsType *ServiceFunctions;
uint8_t ServiceFunctions_size = 0;
//File 4
#include "File2.hpp"
#include <stdlib.h>
void Service_Functions_Setup()
{
ServiceFunctions = NULL;
if(SERVICE_FUNCTION_POINTER_START_SIZE != 0)
{
ServiceFunctions_size = SERVICE_FUNCTION_POINTER_START_SIZE;
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType)*SERVICE_FUNCTION_POINTER_START_SIZE);
for(uint8_t i = 0; i < SERVICE_FUNCTION_POINTER_START_SIZE; i++)
{
ServiceFunctions[i] = NULL;
}
}
}
uint8_t SetServiceFunctionPointer(ServiceFunctionsType a, bool _realloc)
{
if( ServiceFunctions == NULL )
{
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType));
ServiceFunctions[0] = a;
return 0;
}
for(uint8_t i = 0; i < ServiceFunctions_size; i++)
{
if( ServiceFunctions[i] == NULL )
{
ServiceFunctions[i] = a;
return i;
}
}
if(_realloc)
{
ServiceFunctions_size++;
ServiceFunctions = (ServiceFunctionsType*)realloc(ServiceFunctions,sizeof(ServiceFunctionsType)*ServiceFunctions_size);
ServiceFunctions[ServiceFunctions_size - 1] = a;
return ServiceFunctions_size - 1;
}
return INVALID_SERVICE_FUNCTION_POINTER;
}
void ClearServiceFunctionPointer(uint8_t id)
{
ServiceFunctions[id] = NULL;
}
//File 5
class MonoStepSequencer
{
public:
MonoStepSequencer();
~MonoStepSequencer();
uint8_t ServicePointerID;
bool Service(uint32_t time);
private:
};
//File 6
#include "File2.hpp"
MonoStepSequencer::MonoStepSequencer()
{
ServicePointerID = SetServiceFunctionPointer(&this -> Service);
}
//This is the function to be called with a pointer
bool MonoStepSequencer::Service(uint32_t time)
{
//Some Code
}
You can try, to use lambdas. Create method like
std::function<void()> getService()
Where inside you can use:
return [this](){
Service();
};
Also if your methods should use arguments, you can use this method, but add arguments into return value and lambda.
One more, you can create lambda outside of class methods, like:
[&object]()
{
object.Service();
}
In this way, better to use std::shared_ptr to guаrantee that object exists, when lambda called.
this -> Service is an unqualified or parenthesized non-static member function
You probably meant :: instead of -> Also, you need a type on the left, not a variable.
Also, please don't put spaces around ->. That makes it look like you're specifying a trailing return type or something.

Accessing Binary Search Tree in a Function

Consider the following code:
#include "ClassB.h"
ClassA
{
private:
Vector<std::string> idVec;
public:
int getTotal(ClassB& (*func) (std::string));
}
int ClassA::getTotal(ClassB& (*func) (std::string))
{
int total = 0;
for (int i:0; i < idVec.Size(); i++)
{
total += (*func) (idVec[i]).GetInt();
}
return total;
}
ClassB
{
private:
string id;
int i;
public:
std::string getId();
int getInt();
}
ClassB& accessTree(stD::string id);
main()
{
BSTree<ClassB> //Binary Search Tree
ClassA a;
//Assume id's get set.
a.getTotal(accessTree);
}
ClassB& accessTree(stD::string id)
{
//This is part I'm not 100% on.
}
The operators of ClassB have been overloaded. Consider id it's primary key if you will.
**Edit
So Thanks to Joachim Pileborg I've started to use/ learn about placeholders and binding.
Now what I'm about to post is my actual implementation but the concepts are the same. Unit = ClassB. R(aka Registration) = ClassA.
Calling Function
template<typename Ft>
unsigned Registration::GetCredits(Ft func)
{
unsigned sum = 0;
for(unsigned i = 0; i < GetSize(); i++)
sum += results[i].GetCredits(func(results[i].GetUnit()));
return sum;
}
Unit& accessTree(std::string id, BSTree<Unit>& tree)
{
Unit tempU;
tempU.SetId(id);
return tree.search(tempU);
}
In main
R.GetCredits(std::bind(accessTree, _1, std::ref(uTree)));
undefined reference to `unsigned int Registration::GetCredits(std::_Placeholder<1>, std::reference_wrapper >))(std::string, BSTree&)> >(std::_Bind(std::_Placeholder<1>, std::reference_wrapper >))(std::string, BSTree&)>)'|
A little stuck at this point, what have I missed?
Thanks in advance.
There are a couple of solutions to your problems. The most obvious is of course to modify both the getTotal function and the callback function to accept the tree as an extra argument.
Another solution might be to not really use function pointers at all, but to make getTotal a template function, and pass the function type as the template argument. Then you could use std::bind to pass a two-argument function to the getTotal without getTotal not really knowing about the actual function type.
Something like
template<typename Ft>
int ClassA::getTotal(Ft func)
{
...
func(idVec[i]);
...
}
Use it like
ClassB& accessTree(const std::string& id, BSTree<ClassB>& tree);
...
using namespace std::placeholders; // For `_1` etc.
BSTree<ClassB> tree;
a.getTotal(std::bind(accessTree, _1, std::ref(tree)));
(Reference for std::ref)