Hi: please further down find my code.
I compiled using mingw with parameters -Wmain;-pedantic;-std=c++11;-Wall.
Codelite set the semicola between the compiler options
Here I tried to learn how to use thread and mutex: https://en.cppreference.com/w/cpp/thread/mutex
The main module contains the global variable std::mutex mtx after the include section
The thread functions are declared and joined in the main() function; the function definitions for friend class SL can be found here as well. Class and method definitions are spread over the next two modules.
These are the error messages, which I cannot handle:
Message 1
C:/Program Files/CodeBlocks/MinGW/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/thread:240:2: error: no matching function for call to 'std::thread::_Invoker<std::tuple<void (*)(int, int, SL&), int, int, SL> >::_M_invoke(std::thread::_Invoker<std::tuple<void (*)(int, int, SL&), int, int, SL> >::_Indices)'
operator()()
^~~~~~~~
Message 2
C:/Program Files/CodeBlocks/MinGW/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/thread:233:29: error: no matching function for call to '__invoke(std::__tuple_element_t<0, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<1, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<2, std::tuple<void (*)(int, int, SL&), int, int, SL> >, std::__tuple_element_t<3, std::tuple<void (*)(int, int, SL&), int, int, SL> >)'
-> decltype(std::__invoke(_S_declval<_Ind>()...))
__invoke(_Callable&& __fn, _Args&&... __args)
^~~~~~~~
*Message 2 seems to make reference to some type of move constructor ...
I had the idea that the friend function is cause of the dilemma, but was not able to verify
Please help with this.
main module
#include <mutex>
#include <thread>
#include "sl.h"
std::mutex mtx;
void play(int die1, int die2, SL& p){
std::this_thread::sleep_for(std::chrono::seconds(1));
mtx.lock();
if (p.dice.size() > 0) {
p.dice.resize(0);
}
p.set_dice(die1, die2);
rollDice(p);
mtx.unlock();
}
void rollDice(SL& p) {
int iFound = -1;
int iAdd = p.dice[0] + p.dice[1];
p.addPosition(iAdd);
p.bounceBack();
if (p.position == 100) {
printResult(p, iFound);
std::cout << "Game over" << std::endl;
return;
}
if ((iFound = p.check(SL::ladders, p.position)) != -1) {
p.setPosition(SL::ladders[iFound].second);
iFound += 100;
}
else if ((iFound = p.check(SL::snakes, p.position)) != -1) {
p.setPosition(SL::snakes[iFound].second);
}// snakes, position + iAdd
printResult(p, iFound);
if (p.dice[0] == p.dice[1]) {
mtx.unlock();
play(rand() %6 + 1, rand() % 6 + 1, p);
}
}
void printResult(SL& p, int iFound) {
std::cout << ++p.iTimes << ") "
<< p.get_name() << "<<<< "
<< p.dice[0] << "|"
<< p.dice[1] << " position: "
<< p.position;
if (iFound != -1) {
if (iFound > 100) { // this is a ladder field
iFound -= 100;
std::cout << " LADDER from "
<< SL::ladders[iFound].first << "|"
<< SL::ladders[iFound].second;
}
else {
std::cout << " SNAKE from "
<< SL::snakes[iFound].first << "|"
<< SL::snakes[iFound].second;
}
}
std::cout << std::endl;
}
int main()
{
srand(time(NULL));
SL one("Player 1"),
two("Player 2");
std::thread t1 (play, rand() %6 + 1, rand() %6 + 1, one);
std::thread t2 (play, rand() %6 + 1, rand() %6 + 1, two);
while((one.get_position() != 100) && (two.get_position() != 100)) {
t1.join();
t2.join();
}
return 0;
}
// Class Declaration
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <ctime>
#include <iomanip>
class SL {
public:
SL(const std::string& strName) : player(strName), position(0), iTimes(0) {}
~SL() = default;
private:
friend void play(int die1, int die2, SL& p);
friend void rollDice(SL&);
friend void printResult(SL&, int);
static const std::pair<int, int> snakes[];
static const std::pair<int, int> ladders[];
std::string player;
int position;
int iTimes;
std::vector<int> dice;
protected:
int check(const std::pair<int, int> field[], const int iField);
public:
void addPosition(const int iPosition);
void setPosition(const int iPosition);
void bounceBack();
void set_dice(int die1, int die2);
const int get_position() const;
const std::string& get_name() const;
const std::vector<int> get_dice() const;
};
// friend function
void play(int die1, int die2, SL& p);
void rollDice(SL&);
void printResult(SL&, int =-1);
// Class methods - static variables
#include <mutex>
#include <thread>
#include "sl.h"
inline void SL::addPosition(const int iPosition) {
position += iPosition;
}
inline void SL::setPosition(const int iPosition) {
position = iPosition;
}
inline void SL::bounceBack() {
if (position > 100) {
int iBounceBack = position - 100;
position -= iBounceBack;
}
}
inline void SL::set_dice(int die1, int die2){
if (dice.size() > 0) {
dice.erase(dice.begin(), dice.end());
}
dice.push_back(die1);
dice.push_back(die2);
}
const int SL::get_position() const {return position;}
const std::string& SL::get_name() const {return player;}
const std::vector<int> SL::get_dice() const {return dice;}
int SL::check(const std::pair<int, int> field[], const int iField) {
const int end = 10;
int result = -1;
for ( size_t idx = 0; idx < end; idx++) {
if (field[idx].first == iField){
result = idx;
break;
}
else if (iField > field[idx].first)
break;
}
return result;
}
const std::pair<int, int> SL::ladders[] {
std::make_pair( 2, 38),
std::make_pair( 7, 14),
std::make_pair( 8, 31),
std::make_pair(15, 26),
std::make_pair(28, 84),
std::make_pair(36, 44),
std::make_pair(51, 67),
std::make_pair(71, 91),
std::make_pair(78, 98),
std::make_pair(87, 94)
};
const std::pair<int, int> SL::snakes[] {
std::make_pair(16, 6),
std::make_pair(46, 25),
std::make_pair(49, 11),
std::make_pair(62, 19),
std::make_pair(64, 60),
std::make_pair(74, 53),
std::make_pair(89, 68),
std::make_pair(92, 88),
std::make_pair(95, 75),
std::make_pair(99, 80)
};
I tried to go along with G.M.s suggestion and truly I was not able to make it.
For multi threading beginners this is a good stop:
https://hackernoon.com/learn-c-multi-threading-in-5-minutes-8b881c92941f
After reading through all of this I decided for the std::lock guard as so using the mutex mtx global variable from the main module:
void play(int die1, int die2, SL& p){
std::lock_guard<std::mutex> guard(mtx);
if (p.dice.size() > 0) {
p.dice.resize(0);
}
p.setDice(die1, die2);
int iGameOver = 0;
rollDice(p, iGameOver);
if (iGameOver)
return;
}
In the rollDice function I used to have a recursive call to the rollDice function via play. This configuratin caused a dead lock and I got rid of that logic and replaced the recursion into two loops inside main.
int main()
{
srand(time(NULL));
SL one("Player 1"),
two("Player 2");
while((one.getPosition() != 100) && (two.getPosition() != 100)) {
int die1 = 0,
die2 = 0;
if (!two.gameOver()) {
do {
die1 = rand() % 6 + 1;
die2 = rand() % 6 + 1;
play(die1, die2, one);
}while(die1 == die2);
std::cout << "-----------------" << std::endl;
}
if (!one.gameOver()) {
do {
die1 = rand() % 6 + 1;
die2 = rand() % 6 + 1;
play(die1, die2, two);
}while(die1 == die2);
std::cout << "-----------------" << std::endl;
}
}
return 0;
}
The respective logic making another call to rollDice() via play from rollDice was taken off the rollDice function, which now looks like this.
void rollDice(SL& p, int& gameOver) {
int iFound = -1;
int iAdd = p.getAdded();
p.addPosition(iAdd);
p.bounceBack();
if (p.getPosition() == 100)
p.setGameOver();
if (p.gameOver()) {
printResult(p, iFound);
std::cout << "Game over" << std::endl;
return;
}
if ((iFound = p.check(SL::ladders, p.getPosition())) != -1) {
p.setPosition(SL::ladders[iFound].second);
iFound += 100;
}
else if ((iFound = p.check(SL::snakes, p.getPosition())) != -1) {
p.setPosition(SL::snakes[iFound].second);
}// snakes, position + iAdd
printResult(p, iFound);
}
I am not really sure, where I went wrong with my original approach, but my first multi threaded test code is successfully implemented and without me posting and getting G.M.s suggestion, it just would not have taken place. Thank you.
Related
Using a producer-consumer pattern I'd like to submit calls to the member functions of struct A i.e., func_1() and func_2() by passing the name of the function object (something like A::func_1), and a list of arguments taken by these functions in a queue-like buffer queue_in. I'd then like to collect these results (here a std::variant of all the possible return types (double and int)) in another buffer queue_out for later processing.
At the moment, I'm only able to hack my way by having q_in hold std::string and enumerating all the possibilities manually. Of course I'm also missing passing any possible arguments to func_1() and func_2().
#include <iostream>
#include "blockingconcurrentqueue.h" // https://github.com/cameron314/concurrentqueue
#include <variant>
using Result = std::variant<double, int>;
using queue_in = moodycamel::BlockingConcurrentQueue<std::string>;
using queue_out = moodycamel::BlockingConcurrentQueue<Result>;
struct A {
explicit A(queue_in &q_in, queue_out &q_out) {
std::thread t([&]() {
for (;;) {
std::string s;
if (q_in.wait_dequeue_timed(s, -1)) {
if (s == "1")
q_out.enqueue(this->func_1());
else if (s == "2")
q_out.enqueue(this->func_2());
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
t.join();
}
double func_1() const { // func_1 might have arguments!
std::cout << "func_1() called.\n";
return 13.0f;
}
int func_2() const { // func_2 might have arguments!
std::cout << "func_2() called.\n";
return 1;
}
};
void producer(queue_in &q_in, const size_t N) {
for (size_t i = 0; i != N; ++i) {
q_in.enqueue("1" /*..., arguments for func_1*/); // prefer to call the function-object instead
q_in.enqueue("2" /*..., arguments for func_2*/);
}
}
void result_consumer(queue_out &q_out) {
for (;;) {
Result r;
if (q_out.wait_dequeue_timed(r, -1)) {
std::visit([](auto &&arg) {
std::cout << "The result is: " << arg << std::endl;
}, r);
}
std::this_thread::sleep_for(std::chrono::seconds(0));
}
}
int main() {
const size_t N = 2;
queue_in q_in;
queue_out q_out;
std::thread producer_thread(producer, std::ref(q_in), N);
std::thread result_consumer_thread(result_consumer, std::ref(q_out));
A a(q_in, q_out);
producer_thread.join();
result_consumer_thread.join();
}
How can I do this instead via function objects? Second, how do I invoke any possible arguments for the member functions of A. And third, can I avoid the use of a std::variant like result type?
Taking inspiration from #n.1.8e9-where's-my-sharem. 's comments here's how I got the above to work using std::function and std::bind
using Result = std::variant<double, int>;
using FO = std::function<Result(void)>;
using queue_in = moodycamel::BlockingConcurrentQueue<FO>;
using queue_out = moodycamel::BlockingConcurrentQueue<Result>;
struct A {
explicit A(queue_in &q_in, queue_out &q_out) {
std::thread t([&]() {
for (;;) {
FO o;
if (q_in.wait_dequeue_timed(o, -1)) {
q_out.enqueue(o());
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
});
t.detach();
}
void consumer() {
}
double func_1(double x, const size_t &s) const { // note the arguments
std::cout << "func_1() called.\n";
return x + s;
}
int func_2(int x) const {
std::cout << "func_2() called.\n";
return x;
}
};
void producer(const A& a, queue_in &q_in, const size_t N) { // note the first argument: the producer() must know about some instance of A
for (size_t i = 0; i != N; ++i) {
FO o;
if (i % 2 == 0)
o = std::bind(&A::func_1, a, double(i), size_t(10));
else
o = std::bind(&A::func_2, a, int(i));
q_in.enqueue(o);
}
}
void result_consumer(queue_out &q_out) {
for (;;) {
Result r;
if (q_out.wait_dequeue_timed(r, -1)) {
std::visit([&](auto &&arg) {
std::cout << "The result is: " << arg << std::endl;
}, r);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
const size_t N = 2;
queue_in q_in;
queue_out q_out;
A a(q_in, q_out);
std::thread producer_thread(producer, std::ref(a), std::ref(q_in), N);
std::thread result_consumer_thread(result_consumer, std::ref(q_out));
producer_thread.join();
result_consumer_thread.join();
}
Output:
func_1() called.
The result is: 10
func_2() called.
The result is: 1
I have the following problem with my search function.
It expects 3 parameters, and one of them is something like const rational_t* v. I want to pass a vector through that parameter but it doesnt seems to work..
Code:
#include <iostream>
#include <cmath>
#include <vector>
#include "rational_t.hpp"
using namespace std;
bool search(const rational_t* v, const int n, const rational_t& x)
{
for(int i = 0; i < n; i++) {
if(v[i].value() == x.value()) {
return true;
} else {
return false;
}
}
};
int main()
{
rational_t a(1, 2), b(3), c, d(1, 2);
vector<rational_t> v;
v.push_back(a);
v.push_back(b);
v.push_back(c);
cout << "a.value()= " << a.value() << endl;
cout << "b.value()= " << b.value() << endl;
cout << "c.value()= " << c.value() << endl;
cout << search(v, v.size(), d); // Problem here
return 0;
}
I´ve also tried cout << search(v&, v.size(), d); with the reference &.
Any ideas? Thank You.
The class :
#pragma once
#include <iostream>
#include <cassert>
#include <cmath>
#define EPSILON 1e-6
using namespace std;
class rational_t
{
int num_, den_;
public:
rational_t(const int = 0, const int = 1);
~rational_t() {}
int get_num() const
{
return num_;
}
int get_den() const
{
return den_;
}
void set_num(const int n)
{
num_ = n;
}
void set_den(const int d)
{
assert(d != 0), den_ = d;
}
double value(void) const;
rational_t opposite(void) const;
rational_t reciprocal(void) const;
bool equal(const rational_t &r, const double precision = EPSILON) const;
bool greater(const rational_t &r, const double precision = EPSILON)
const;
bool less(const rational_t &r, const double precision = EPSILON) const;
bool cero_equal(const double precision) const;
void write(ostream &os = cout) const;
void read(istream &is = cin);
};
The first argument of search should be a rational_t* but you're passing a vector<rational_t>.
You want
search(v.data(), v.size(), d)
instead of
search(v, v.size(), d)
But I'd write this like this which is cleaner IMO:
bool search(vector<rational_t> & v, const rational_t& x)
{
for (int i = 0; i < v.size(); i++) {
if (v[i].value() == x.value()) {
return true;
}
else {
return false;
}
}
}
...
cout << search(v, d);
After a bit of bug searching, I've found that my code leaves with exit code 11 at a certain point, and this is because an EXC_BAD_ACCESS error with code 1. After some googling, I see this must be due to some memory mismanagement, but I'm new to C++ and nothing seems obvious to me.
The code is exiting at the line
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
in the file (last function)
//
// Created by Anthony Monterrosa on 4/17/18.
//
#include "MathExpr.h"
#include <list>
#include <iostream>
#include <random>
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::NumType> &)>> MathExpr::layerFuncts;
std::vector<std::function<void(std::vector<MathExpr::CharType> &, MathExpr::NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> MathExpr::fieldFuncts;
void MathExpr::init() {
initLayerFuncts();
initFieldFuncts();
}
void MathExpr::initLayerFuncts() {
layerFuncts.resize(Op::EOOE);
layerFuncts[static_cast<unsigned long>(Op::addition)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::addition), ' '});
equal += otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
layerFuncts[static_cast<unsigned long>(Op::subtraction)] = [](std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, std::vector<NumType> & otherArgs) -> void {
string.insert(string.end(), {' ', opToChar(Op::subtraction), ' '});
equal -= otherArgs[0];
std::vector<MathExpr::CharType> digits = intToDigit(otherArgs[0]);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
};
}
void MathExpr::initFieldFuncts() {
fieldFuncts.resize(Field::EOFE);
fieldFuncts[static_cast<unsigned long>(Field::integers)] = [](std::vector<MathExpr::CharType> &string, NumType &equal, std::vector<MathExpr::Op> &validOps, unsigned char length, unsigned char difficulty, std::mt19937 &rng, std::uniform_int_distribution<MathExpr::OpType> &opGen) -> void {
std::uniform_int_distribution<MathExpr::NumType> numGen(1, static_cast<MathExpr::NumType>(pow(10, difficulty)));
equal = numGen(rng);
std::vector<MathExpr::CharType> digits = intToDigit(equal);
for(int i = 0; i < digits.size(); i++ ) {
string.push_back(digits[i]);
}
for (int i = 0; i < length - 1; i++) {
MathExpr::Op op = validOps[opGen(rng)];
int count = otherArgsCount(op);
std::vector<MathExpr::NumType> otherArgs(count);
for(int j = 0; j < count; j++) {
otherArgs[j] = (numGen(rng));
}
layer(string, equal, op, otherArgs);
}
};
}
char MathExpr::opToChar(OpType ordinal) {
return opToChar(static_cast<Op>(ordinal));
}
char MathExpr::opToChar(Op op) {
switch(op) {
case Op::addition : return '+';
case Op::subtraction : return '-';
default : return '_';
}
}
MathExpr::NumType MathExpr::otherArgsCount(MathExpr::Op op) {
switch(op) {
case Op::addition : return 1;
case Op::subtraction : return 1;
default : return 0;
}
}
std::vector<MathExpr::CharType> MathExpr::intToDigit(MathExpr::NumType num) {
std::vector<MathExpr::CharType> digits;
while(num >= 10) {
digits.insert(digits.begin(),'0' + static_cast<MathExpr::CharType>(num % 10));
num /= 10;
} digits.insert(digits.begin(), '0' + static_cast<MathExpr::CharType>(num));
return digits;
}
bool MathExpr::initBool = false;
MathExpr::MathExpr(std::vector<CharType> exp, MathExpr::NumType equal) {
if(!initBool) init();
this->string = std::vector<CharType>(exp);
this->equal = equal;
}
void MathExpr::print(MathExpr &exp) {
for(int i = 0; i < exp.string.size(); i++) {
std::cout << exp.string[i];
}
}
void MathExpr::layer(std::vector<MathExpr::CharType> &string, MathExpr::NumType &equal, MathExpr::Op op, std::vector<MathExpr::NumType> &otherArgs) {
layerFuncts[op](string, equal, otherArgs);
}
MathExpr MathExpr::generate(std::vector<MathExpr::Op> &validOps, MathExpr::Field field, unsigned char length, unsigned char difficulty) {
std::vector<MathExpr::CharType> string;
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<MathExpr::OpType> opGen(0, static_cast<MathExpr::OpType>(validOps.size() - 1));
MathExpr::NumType equal;
fieldFuncts[field](string, equal, validOps, length, difficulty, rng, opGen);
return MathExpr::MathExpr(string, equal);
}
here is the corresponding .h file
//
// Created by Anthony Monterrosa on 4/17/18.
//
// EO_E -> "end of _ enum".
#ifndef MATHTESTGENERATOR_MATHEXPR_H
#define MATHTESTGENERATOR_MATHEXPR_H
#include <functional>
#include <random>
#include <vector>
class MathExpr {
public:
using FieldType = unsigned char;
using OpType = unsigned char;
using NumType = short int;
using CharType = char;
enum Field : FieldType {
integers,
EOFE // rational, real, complex.
};
enum Op : OpType {
addition,
subtraction,
EOOE // multiplication, division, absolute value, radical
};
explicit MathExpr(std::vector<CharType>, NumType);
std::vector<CharType> string;
NumType equal;
static void print(MathExpr &);
static MathExpr generate(std::vector<Op> &, Field = Field::integers, unsigned char length = 2, unsigned char difficulty = 1);
//protected:
static void init();
static bool initBool;
static void layer(std::vector<MathExpr::CharType> &, NumType &, Op, std::vector<NumType> &);
static NumType otherArgsCount(Op);
static std::vector<CharType> intToDigit(NumType);
static char opToChar(OpType);
static char opToChar(Op);
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<NumType> &)>> layerFuncts;
static void initLayerFuncts();
static std::vector<std::function<void(std::vector<MathExpr::CharType> &, NumType &, std::vector<MathExpr::Op> &, unsigned char, unsigned char, std::mt19937 &, std::uniform_int_distribution<MathExpr::OpType> &)>> fieldFuncts;
static void initFieldFuncts();
};
#endif //MATHTESTGENERATOR_MATHEXPR_H
My gut says the error has to do with the "string" vector, but I'm unsure of how to tell. I would appreciate insight into the problem.
I am writing to perform and test a binary search. The aim is to get the maximum x when y<=0 for the function y=x-1, and the search range is [-2,2),obviously the answer should be 1.
for test part, I should test if the invocations of function f is less than the calculated max_invoke
a segmentation fault appeared, and when I valgrind it, the error is:
==126667== Use of uninitialised value of size 8
==126667== at 0x400C8A: binarySearchForZero(Function<int, int>*, int,
int) (in /home/jw562/ece551/092_tests_binsrch/test)
==126667== by 0x400DD5: check(Function<int, int>*, int, int, int,
char const*) (in /home/jw562/ece551/092_tests_binsrch/test)
==126667== by 0x400E81: main (in
/home/jw562/ece551/092_tests_binsrch/test)
==126667== Uninitialised value was created by a stack allocation
==126667== at 0x400E41: main (in
/home/jw562/ece551/092_tests_binsrch/test)
below is my code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
template<typename R, typename A>
class Function {
public:
virtual R invoke(A arg) = 0;
virtual ~Function() {}
};
class CountedIntFn : public Function<int,int>{
protected:
unsigned remaining;
Function<int,int> * f;
const char * mesg;
public:
CountedIntFn(unsigned n, Function<int,int> * fn, const char * m):
remaining(n),f(fn),mesg(m) {}
virtual int invoke(int arg) {
if (remaining == 0) {
fprintf(stderr,"Too many function invocations in %s\n", mesg);
exit(EXIT_FAILURE);
}
remaining--;
return f->invoke(arg);
}
class linearFunction : public Function<int, int> {
public:
virtual int invoke(int arg) {
int ans = arg-1;
return ans;
}
virtual ~linearFunction(){}
};
int binarySearchForZero(Function<int, int> * f, int low, int high){
if (high <= low){
cout << "high less or equal than low" << endl;
return EXIT_FAILURE;
}
int low_ans = f->invoke(low);
int high_ans = f->invoke(high);
int mid = (high-low)/2+low;
int mid_ans = f->invoke(mid);
if (low_ans > 0){
return low;//all positive
}
if (high_ans < 0){
return high-1;//all negtive
}
if (low_ans = high_ans){
return low;//all zero
}
if (mid_ans <= 0){
low = mid;
}
if (mid_ans >= 0){
high = mid;
}
return binarySearchForZero(f,low,high);
}
void check(Function<int,int> * f,int low,int high,int
expected_ans,const char * mesg){
int max_invoke = 0;//the maximum number of invocations allowed
if (high > low){
max_invoke = (int)(log2(high-low))+1;
}
else {
max_invoke = 1;
}
CountedIntFn count(max_invoke,f,mesg);
int ans = binarySearchForZero(f,low,high);
if (ans != expected_ans){
cout << "wrong answer" <<endl;
}
}
int main(void){
linearFunction *fl;
const char * message = "linearFunction";
int low = -2;
int high = 2;
int expected_ans = 1;
check(fl,low,high,expected_ans,message);
return EXIT_SUCCESS;
}
This is because variable fl of type linearFunction* is uninitialized.
You can change it to a non-pointer, and invoke with address-of operator:
linearFunction fl;
...
check(&fl, low, high, expected_ans, message);
I am trying to grasp pointer function concept in a better way. So I have a very simple and working example as:
#include <iostream>
using namespace std;
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int (*functocall)(int, int))
{
return (*functocall)(first, second);
}
int main()
{
int a, b;
int (*plus)(int, int);
int (*minus)(int, int);
plus = &add;
minus = &subtract;
a = operation(7, 5, add);
b = operation(20, a, minus);
cout << "a = " << a << " and b = " << b << endl;
return 0;
}
So far so good,
Now I need to group the functions in a class, and select add or subtract based on the function pointer that i use. So I just make a small modification as:
#include <iostream>
using namespace std;
class A
{
public:
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int (*functocall)(int, int))
{
return (*functocall)(first, second);
}
};
int main()
{
int a, b;
A a_plus, a_minus;
int (*plus)(int, int) = A::add;
int (*minus)(int, int) = A::subtract;
a = a_plus.operation(7, 5, plus);
b = a_minus.operation(20, a, minus);
cout << "a = " << a << " and b = " << b << endl;
return 0;
}
and the obvious error is:
ptrFunc.cpp: In function ‘int main()’:
ptrFunc.cpp:87:29: error: invalid use of non-static member function ‘int A::add(int, int)’
ptrFunc.cpp:88:30: error: invalid use of non-static member function ‘int A::subtract(int, int)’
coz I haven't specified which object to invoke(and I don't want to use static methods for now)
EDIT:
several comments and answers suggested that the non-static version(as I have written) is not possible.(thanks to all)
So,
Modifying the class in the following manner also wont work:
#include <iostream>
using namespace std;
class A
{
int res;
public:
A(int choice)
{
int (*plus)(int, int) = A::add;
int (*minus)(int, int) = A::subtract;
if(choice == 1)
res = operation(7, 5, plus);
if(choice == 2)
res = operation(20, 2, minus);
cout << "result of operation = " << res;
}
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int (*functocall)(int, int))
{
return (*functocall)(first, second);
}
};
int main()
{
int a, b;
A a_plus(1);
A a_minus(2);
return 0;
}
generated this error:
ptrFunc.cpp: In constructor ‘A::A(int)’:
ptrFunc.cpp:11:30: error: cannot convert ‘A::add’ from type ‘int (A::)(int, int)’ to type ‘int (*)(int, int)’
ptrFunc.cpp:12:31: error: cannot convert ‘A::subtract’ from type ‘int (A::)(int, int)’ to type ‘int (*)(int, int)’
may I know how to solve this issue please?
thanks
The syntax to declare a function pointer to member methods is:
int (A::*plus)(int, int) = &A::add;
int (A::*minus)(int, int) = &A::subtract;
To invoke member methods use .* or ->* operator:
(a_plus.*plus)(7, 5);
Also have a look at http://msdn.microsoft.com/en-us/library/b0x1aatf(v=vs.80).aspx
Hope this helps.
Complete code:
#include <iostream>
using namespace std;
class A
{
public:
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int (A::*functocall)(int, int))
{
return (this->*functocall)(first, second);
}
};
int main()
{
int a, b;
A a_plus, a_minus;
int (A::*plus)(int, int) = &A::add;
int (A::*minus)(int, int) = &A::subtract;
a = a_plus.operation(7, 5, plus);
b = a_minus.operation(20, a, minus);
cout << "a = " << a << " and b = " << b << endl;
return 0;
}
You can't pass non-static member function as argument that easy. And for your needs, I believe it's better to override operators: http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/
But if you really need them as actual member functions - just make them static.
The edit you made to your code is still wrong because it doesn't make the member functions static. You need to make the add, subtract etc. functions static by adding the static specifier:
#include <iostream>
using namespace std;
class A
{
int res;
public:
A(int choice)
{
int (*plus)(int, int) = A::add;
int (*minus)(int, int) = A::subtract;
if(choice == 1)
res = operation(7, 5, plus);
if(choice == 2)
res = operation(20, 2, minus);
cout << "result of operation = " << res;
}
static int add(int first, int second)
{
return first + second;
}
static int subtract(int first, int second)
{
return first - second;
}
static int operation(int first, int second, int (*functocall)(int, int))
{
return (*functocall)(first, second);
}
};
See the below code. The function calls are working without making them static.
class A
{
public:
int add(int first, int second)
{
return first + second;
}
int subtract(int first, int second)
{
return first - second;
}
int operation(int first, int second, int(A::*functocall)(int, int))
{
return (this->*functocall)(first, second);
}
};
//typedef int(A::*PFN)(int, int) ;
int main()
{
int a, b;
A a_plus, a_minus;
a = a_plus.operation(7, 5, &A::add);
b = a_minus.operation(20, a, &A::subtract);
cout << "a = " << a << " and b = " << b << endl;
return 0;
}