Accessing Binary Search Tree in a Function - c++

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)

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

C++: Passing a non moveable functor to a std::function

How can one pass a non moveable object to a std::function? One easy enough alternative is passing a std::reference_wrapper which would create the need for the lifecycle of function be dependant on the object. Example code follows to explain the issue better.
class Player {
std::atomic_int runs {0};
std::string name;
public:
Player(std::string&& name) : name(std::move(name)) {} //...
void inc() { ++runs;}
};
class PlayerStats {
std::array<std::unique_ptr<Player>,2> players;
public:
PlayerStats() {
for(int i = 0; i<2 ; i++)
players[i] = std::unique_ptr<Player>(new Player{"player"+std::to_string(i)});
}
Player* const operator() (int index) const {
return players[index].get();
}
};
using player_total_f = std::function<Player* const(int index)>;
class GameStats {
std::string game;
std::string date;
player_total_f f;
public:
GameStats(std::string&& game, std::string&& date, player_total_f&& _f) :
game(std::move(game)), date(std::move(date)), f(std::move(_f)) {}
};
int main(int argc, char *argv[])
{
PlayerStats st;
//GameStats("game1","10.11",std::ref(st)); //this seems like the only possibility, no way to make GameStats own the functor
return 0;
}
How can I set the function here to PlayerStats, given that it is non copyable, a std::ref seems to be like the only possibility?
template<class F>
auto shared_function( F&& f ){
auto spf=std::make_shared<std::decay_f<F>>(std::forward<F>(f));
return [spf=std::move(spf)](auto&&...args)->decltype(auto){
return (*pf)(decltype(args)(args)...);
};
}
own it in a shared ptr. Changes semantics a bit, but fixes it.
Or write your own non-copying std function.

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

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.

Sorting a vector of a class

I have class called "UltrasoundTemplate". These UltrasoundTemplate objects contain an int parameter, which shows when they where defined (something like a time stamp). And I have a class called "UltrasoundTarget" which contains a vector of UltrasoundTemplate's.
I add UltrasoundTemplates to the vector with push_back(ultrasoundTemplate).
Now I want to sort the vector by the order of time stamps instead of the order I added them to the vector.
I found a lot of answers in google, which all show me the same solution, but obviously I'm still doing something wrong. Here are the code snippets I think are necessary for finding a solution:
ultrasoundTemplate.h
class UltrasoundTemplate
{
public:
UltrasoundTemplate(/*...*/);
int getVolumePos() { return volume_; }
private:
int volume_;
};
ultrasoundTarget.h
//the sort algorithm
struct MyTemplateSort {
bool operator() ( UltrasoundTemplate t1, UltrasoundTemplate t2){
int it1 = t1.getVolumePos();
int it2 = t2.getVolumePos();
if (it1 < it2)
return true;
return false;
}
};
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
FMainWindow.cpp
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName) {
//here I try to sort
MyTemplateSort tmpltSrt;
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
break;
}
}
As an example: I define Template1 in Volume(0), Template2 in Volume(70) and Template3 in Volume(40). The order now is (Template1, Template2, Template3) but I want it to be (Template1, Template3, Template2). But this code is not doing it.
If there's Information missing, just tell me and I'll provide more code.
Thanks alot.
Your getTemplates() method returns by value, making a mess here:
std::sort(USTargetVector.at(i).getTemplates().begin(),
USTargetVector.at(i).getTemplates().end(), tmpltSrt);
You are sorting an incompatible iterator range. You can fix that particular problem by returning a reference:
vector<UltrasoundTemplate>& getTemplates() { return USTemplateVector_; }
It is common practice to add a const overload to such a method:
const vector<UltrasoundTemplate>& getTemplates() const { return USTemplateVector_; }
You can also modify your comparison functor to avoid unnecessary copies (and for general readability and const correctness):
struct MyTemplateSort {
bool operator() const ( const UltrasoundTemplate& t1, const UltrasoundTemplate& t2)
{
return t1.getVolumePos() < t2.getVolumePos();
}
};
This will require that you make getVolumePos() a const method, which it should be anyway:
class UltrasoundTemplate
{
public:
...
int getVolumePos() const { return volume_; }
...
};
Note that is is not generally good practice to provide references to the private data of a class. If possible, you should find a way to remove that from the UltraSoundTarget interface. You could, for instance, expose a pair of iterators, and/or give the class a sort method.
juanchopanza answer is correct, the problem is the way you are returning the vector from UltrasoundTarget. Just to touch another topic, maybe it would be nice to change a little the designing of your implementation. As UltrasoundTarget is a container of Ultrasound's, it makes sense to implement the sort as a method of this class, this way you have direct access to USTemplateVector_ and will save unecessary copies. Something like:
class UltrasoundTarget
{
public:
UltrasoundTarget(/*...*/);
vector<UltrasoundTemplate> getTemplates() { return USTemplateVector_; }
void sort();
private:
vector<UltrasoundTemplate> USTemplateVector_;
};
void UltrasoundTarget::sort()
{
std::sort(USTemplateVector_.begin(), USTemplateVector_.end(), tmpltSrt);
}
void FMainWindow::match_slot()
{
int i;
//here I get the name of the target I'm looking for
QTreeWidgetItem *item = targetInfoWidget_->treeWidget->currentItem();
int index = targetInfoWidget_->treeWidget->indexOfTopLevelItem(item);
QString itemToAppendName = item->text(0);
for(i = 0; i < USTargetVector.size(); i++){
if(USTargetVector.at(i).getName() == itemToAppendName)
{
//here I try to sort
MyTemplateSort tmpltSrt;
USTargetVector.at(i).sort();
break;
}
}

How do I repass a function pointer in C++

Firstly, I am very new to function pointers and their horrible syntax so play nice.
I am writing a method to filter all pixels in my bitmap based on a function that I pass in. I have written the method to dereference it and call it in the pixel buffer but I also need a wrapper method in my bitmap class that takes the function pointer and passes it on. How do I do it? What is the syntax? I'm a little stumped.
Here is my code with all the irrelevant bits stripped out and files combined (read all variables initialized filled etc.).
struct sColour
{
unsigned char r, g, b, a;
};
class cPixelBuffer
{
private:
sColour* _pixels;
int _width;
int _height;
int _buffersize;
public:
void FilterAll(sColour (*FilterFunc)(sColour));
};
void cPixelBuffer::FilterAll(sColour (*FilterFunc)(sColour))
{
// fast fast fast hacky FAST
for (int i = 0; i < _buffersize; i++)
{
_pixels[i] = (*FilterFunc)(_pixels[i]);
}
}
class cBitmap
{
private:
cPixelBuffer* _pixels;
public:
inline void cBitmap::Filter(sColour (*FilterFunc)(sColour))
{
//HERE!!
}
};
If I understand what you want:
inline void cBitmap::Filter(sColour (*FilterFunc)(sColour))
{
_pixels->FilterAll( FilterFunc);
}
Often dealing with function pointers can be made easier to read if you use a typedef for the function pointer type (yours actually isn't too bad on its own - they can get much worse very easily):
struct sColour
{
unsigned char r, g, b, a;
};
typedef
sColour (*FilterFunc_t)(sColour); // typedef for a FilterFunc
class cPixelBuffer
{
private:
sColour* _pixels;
int _width;
int _height;
int _buffersize;
public:
void FilterAll(FilterFunc_t FilterFunc);
};
void cPixelBuffer::FilterAll(FilterFunc_t FilterFunc)
{
// fast fast fast hacky FAST
for (int i = 0; i < _buffersize; i++)
{
_pixels[i] = (*FilterFunc)(_pixels[i]);
}
}
class cBitmap
{
private:
cPixelBuffer* _pixels;
public:
inline void cBitmap::Filter(FilterFunc_t FilterFunc)
{
_pixels->FilterAll( FilterFunc);
}
};
The Boost libraries can make your life easier here. see boost function.
For example here is a function that takes a call back function that takes two ints and returns an int:
void do_something( boost::function<int (int, int)> callback_fn );
Then it can be used like a normal function:
int result = callback_fn(1,2);
Pass it to do_something like this:
boost::function<int (int, int)> myfn = &the_actual_fn;
do_something(myfn);
With boost function you can also pass class member functions easily (see boost bind).
Good luck with your program.
You could make things clearer by using a typedef for your function pointer type:
typedef sColour (*FilterFunc_t)(sColour)
void FilterAll(FilterFunc_t FilterFunc);
Passing a variable containing a function pointer to a different function works the same as passing any other variable:
inline void cBitmap::Filter(FilterFunc_t FilterFunc) {
FilterAll(FilterFunc);
}