I try to implement Scott Mayer book code example, the example is about calling functor through function object
the header file gameCharachter.h
#ifndef GAMECHARACTER_H
#define GAMECHARACTER_H
#include <iostream>
#include <typeinfo>
using namespace std;
#include <tr1/functional>
class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter
{
public:
typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;
explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: healthFunc(hcf)
{
}
~GameCharacter()
{
}
int healthValue() const
{
return healthFunc(*this);
}
private:
HealthCalcFunc healthFunc;
};
class EyeCandyCharacter: public GameCharacter // another character
{
public:
explicit EyeCandyCharacter(HealthCalcFunc hcf = defaultHealthCalc)
: GameCharacter(hcf)
{
cout<<typeid(*this).name()<<"::"<<__FUNCTION__<<""<<endl;
}
};
struct HealthCalculator
{
/*explicit*/ HealthCalculator()
{
}
int operator()(const GameCharacter& gc) const // calculation function
{
cout<<typeid(*this).name()<<"::"<<__FUNCTION__<<""<<endl;
return 0;
}
};
#endif // GAMECHARACTER_H
the main.cpp is :
#include "gamecharacter.h"
int main()
{
EyeCandyCharacter ecc1(HealthCalculator());
ecc1.healthValue();
}
why function<> object refuse to call the operator() function in healthvalue()
EyeCandyCharacter ecc1(HealthCalculator());
declares a function called ecc1 that takes an argument of type "pointer to function taking no arguments and returning a HealthCalculator" and returns a EyeCandyCharacter. I assume that this isn't your intent.
this is the correct call , it should be called by bind
#include "gamecharacter.h"
int main()
{
HealthCalculator hc;
EyeCandyCharacter ecc1(std::tr1::bind(&HealthCalculator::operator(),hc,tr1::placeholders::_1));
ecc1.healthValue();
}
Related
I hope to use map library to call a function by a string with the function name, I've tested the following example and everything are working well.
#include <string>
#include <iostream>
using namespace std;
typedef void (*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &func1;//
}
void callFunc(const std::string& str)
{
(*strFuncMap[str])();
}
int main()
{
buildMap();
callFunc("func1");
return 0;
}
However, as I define all these things in a class, there is a compiler error occur:
#include <map>
#include <string>
#include <iostream>
using namespace std;
class theClass {
public:
typedef void (*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &func1;// a value of type cannot be assigned to an entity of type
}
void callFunc(const std::string& str)
{
(*strFuncMap[str])();
}
};
int main()
{
theClass a;
a.buildMap();
a.callFunc("func1");
return 0;
}
I've tried to solve this problem for a couple of hours. Or is there any other way to use string to call function in a class? I will very appreciate if someone can help me. THANKS!!
Your code doesn't work because func1 is a member function and the syntax for member functions is different.
You need a map of member function pointers (offsets)
typedef void (theClass::*pFunc)();
map<string, pFunc> strFuncMap;
Then you can store the pointer with
strFuncMap["func1"] = &theClass::func1;
And you need an object to call a member function
(this->*strFuncMap[str])();
The final code:
#include <map>
#include <string>
#include <iostream>
using namespace std;
class theClass {
public:
typedef void (theClass::*pFunc)();
map<string, pFunc> strFuncMap;
void func1()
{
printf("this is func1!\n");
}
void buildMap()
{
strFuncMap["func1"] = &theClass::func1;
}
void callFunc(const std::string& str)
{
(this->*strFuncMap[str])();
}
};
int main()
{
theClass a;
a.buildMap();
a.callFunc("func1");
return 0;
}
typedef void (*pFunc)();
This declares pFunc to be the type of function pointers. That is, the type of pointers to functions which exist at the top-level. This excludes member functions, lambda functions, and functors. Consider
using pFunc = std::function<void()>
Now your type will correctly accept anything that can reasonably be interpreted as a callable object. Note that member functions still need to be wrapped in a lambda, since you're closing around this.
strFuncMap["func1"] = [this]() { this->func1(); };
In below code snippet while calling call back function "Invalid use of void expression" error
is flashed by the compiler.
#include <iostream>
#include <functional>
using namespace std;
template<class type>
class State {
public:
State(type type1,const std::function<void (type type1 )> Callback)
{
}
};
template <class type>
void Callback(type type1 )
{
//Based on type validation will be done here
}
int main()
{
State<int> obj(10,Callback(10));
return 0;
}
Just want to know what is the wrong here so that same can be addressed .
It seems that you want to pass the Callback<int> function itself, not its return value (which there is none), to the constructor of obj. So do just that:
State<int> obj(10, Callback<int>);
Your current code actually calls Callback(10) first and then tries to take its void "return value" to pass it to the constructor of obj. Passing void is not allowed in C++, which is why the compiler is complaining. (Callback(10) is the "void expresson" here.)
I guess this is what you want
#include <iostream>
#include <functional>
using namespace std;
template<class type>
class State {
public:
State(type type1,const std::function<void (type)> callback)
{
callback(type1);
}
};
template <class type>
void Callback(type type1 )
{
}
int main()
{
State<int> obj(10, Callback<int>);
return 0;
}
I would like to go with lambda expression approach to avoid the confusion :
#include <iostream>
#include <functional>
using namespace std;
template<class type>
class State
{
public:
State( type type1, const std::function<void (type type1 )> Callback)
{
Callback(type1);
}
};
int main()
{
State<int > monitor(10,[] ( int fault) {std::cout<<"Any Message"; });
return 0;
}
I'm trying to write mock for a class which contains three overloaded methods, ie.:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using ::testing::_;
using ::testing::Return;
using ::testing::A;
using ::testing::ByRef;
using ::testing::Ref;
using ::testing::TypedEq;
struct Foo {
int fooMethod(const int& intParam) { return 0; }
int fooMethod(const float& floatParam) { return 0; }
int fooMethod(const std::string& stringParam) { return 0; }
};
struct FooMock {
FooMock() {
ON_CALL(*this, fooMethod(_)).WillByDefault(Return(-1));
}
MOCK_METHOD1(fooMethod, int(const int& intParam));
MOCK_METHOD1(fooMethod, int(const float& floatParam));
MOCK_METHOD1(fooMethod, int(const std::string& stringParam));
};
but this gives an error:
error: call of overloaded ‘gmock_fooMethod(const testing::internal::AnythingMatcher&)’ is ambiguous
I've also tried TypedEq() instead of "_", but it gives more obscure errors. I've checked GMock FAQ, Wiki and I didn't find solution - how can I return default value with ON_CALL for overloaded methods?
BR,
Lukasz
#tx34 has the crux of the answer, but there are a few more issues in the code.
Firstly, the docs on Selecting Between Overloaded Functions are most appropriate. You have three overloads of fooMethod with the same number of arguments but different argument types. You're going to have to use a matcher that specifies the type.
Next, you need to define all your Foo functions which are to be mocked as virtual, or else invoking them through a Foo object won't call the derived mock functions. Since you're defining Foo as a base class, it should also have a virtual destructor to avoid slicing.
Finally, you need to have FooMock inherit from Foo.
So putting it all together, you end up with something like:
#include <memory>
#include <string>
#include "gtest/gtest.h"
#include "gmock/gmock.h"
using ::testing::_;
using ::testing::An;
using ::testing::Matcher;
using ::testing::TypedEq;
using ::testing::Return;
struct Foo {
virtual ~Foo() {}
virtual int fooMethod(const int&) { return 0; }
virtual int fooMethod(const float&) { return 0; }
virtual int fooMethod(const std::string&) { return 0; }
};
struct FooMock : Foo {
FooMock() : Foo() {
ON_CALL(*this, fooMethod(An<const int&>())).
WillByDefault(Return(-1));
ON_CALL(*this, fooMethod(Matcher<const float&>(_))).
WillByDefault(Return(-2));
ON_CALL(*this, fooMethod(TypedEq<const std::string&>("1"))).
WillByDefault(Return(-3));
}
MOCK_METHOD1(fooMethod, int(const int& intParam));
MOCK_METHOD1(fooMethod, int(const float& floatParam));
MOCK_METHOD1(fooMethod, int(const std::string& stringParam));
};
TEST(Foo, foo) {
std::shared_ptr<Foo> foo(new FooMock);
auto foo_mock(std::dynamic_pointer_cast<FooMock>(foo));
EXPECT_CALL(*foo_mock, fooMethod(Matcher<const int&>(_))).Times(1);
EXPECT_CALL(*foo_mock, fooMethod(Matcher<const float&>(_))).Times(1);
EXPECT_CALL(*foo_mock, fooMethod(Matcher<const std::string&>(_))).Times(1);
EXPECT_EQ(-1, foo->fooMethod(1));
EXPECT_EQ(-2, foo->fooMethod(1.0f));
EXPECT_EQ(-3, foo->fooMethod("1"));
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
The problem is TypedEq expects a value not a matcher. You can achieve what you want by:
ON_CALL(*this, fooMethod(An<ArgType>())).WillByDefault(Return(-1));
or
ON_CALL(*this, fooMethod(Matcher<ArgType>(_))).WillByDefault(Return(-1));
See also:
https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md#selecting-between-overloaded-functions-selectoverload
https://github.com/google/googletest/blob/master/docs/gmock_cheat_sheet.md#wildcard
https://github.com/google/googletest/blob/master/docs/gmock_cheat_sheet.md#generic-comparison
I try to compile the following code:
#include <cppunit/extensions/HelperMacros.h>
#include "tested.h"
class TestTested : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestTested);
CPPUNIT_TEST(check_value);
CPPUNIT_TEST_SUITE_END();
public:
void check_value();
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestTested);
void TestTested::check_value() {
tested t(3);
int expected_val = t.getValue(); // <----- Line 18.
CPPUNIT_ASSERT_EQUAL(7, expected_val);
}
As a result I get:
testing.cpp:18:32: Error: void-value is not ignored where it should be
EDDIT
To make the example complete I post the code of the tested.h and tested.cpp:
tested.h
#include <iostream>
using namespace std;
class tested {
private:
int x;
public:
tested(int int_x);
void getValue();
};
tested.cpp
#include <iostream>
using namespace std;
tested::tested(int x_inp) {
x = x_inp;
}
int tested::getValue() {
return x;
}
you declare void getValue(); in the class tested.. change to int getValue();.
A void function cannot return a value.
You are getting a value of int from the API getValue(), hence it should return an int.
Your class definition doesn't match the implementation:
In your header you've declared it in the following way (as an aside, you might want to look into some naming conventions).
class tested {
private:
int x;
public:
tested(int int_x);
void getValue();
};
You've declared getValue() as void, i.e no return. Doesn't make much sense for a getter to return nothing, does it?
However, in the .cpp file you've implemented getValue() like so:
int tested::getValue() {
return x;
}
You need to update the getValue() method signature in the header type so that its return type matches the implementation (int).
I am trying to create a generic function map using templates.The idea is to inherit from this generic templated class with a specific function pointer type. I can register a function in the global workspace, but I'd rather collect all the functions together in the derived class and register these in the constructor. I think I am almost here but I get a compile error. Here is a stripped down version of my code:
#include <iostream>
#include <string>
#include <map>
#include <cassert>
using namespace std;
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef int (*F)(int);
// function factory
template <typename T>
class FunctionMap {
public:
void registerFunction(string name, T fp) {
FunMap[name] = fp;
}
T getFunction(string name) {
assert(FunMap.find(name) != FunMap.end());
return FunMap[name];
}
private:
map<string, T> FunMap;
};
// specific to integer functions
class IntFunctionMap : public FunctionMap<F> {
public:
int f2(int x) { return 2 * x; }
int g2(int x) { return -3 * x; }
IntFunctionMap() {
registerFunction("f", f); // This works
registerFunction("f2", f2); // This does not
}
};
int main()
{
FunctionMap<F> fmap; // using the base template class directly works
fmap.registerFunction("f", f);
F fun = fmap.getFunction("f");
cout << fun(10) << endl;
return 0;
}
The error I get is:
templatefunctions.cpp: In constructor ‘IntFunctionMap::IntFunctionMap()’:
templatefunctions.cpp:33: error: no matching function for call to ‘IntFunctionMap::registerFunction(const char [3], <unresolved overloaded function type>)’
templatefunctions.cpp:15: note: candidates are: void FunctionMap<T>::registerFunction(std::string, T) [with T = int (*)(int)]
Juan's answer is correct: member functions have an implicit first parameter, which is a pointer to the type of which they are a member. The reason your code fails to compile is that your map supports function pointers with type int (*)(int), but the type of f2 is int (IntFunctionMap::*)(int).
In the specific case that you show here, you can use std::function, which implements types erasure, to present free functions and member functions as the same type. Then you could do what you are trying to do. Note: this requires C++11.
#include <iostream>
#include <string>
#include <map>
#include <cassert>
#include <function>
#include <bind>
using namespace std;
int f(int x) { return 2 * x; }
int g(int x) { return -3 * x; }
typedef std::function<int (int)> F;
// function factory
template <typename T>
class FunctionMap {
public:
void registerFunction(string name, T fp) {
FunMap[name] = fp;
}
T getFunction(string name) {
assert(FunMap.find(name) != FunMap.end());
return FunMap[name];
}
private:
map<string, T> FunMap;
};
// specific to integer functions
class IntFunctionMap : public FunctionMap<F> {
public:
int f2(int x) { return 2 * x; }
int g2(int x) { return -3 * x; }
IntFunctionMap() {
registerFunction("f", f); // This works
registerFunction("f2", std::bind(&f2, this, _1)); // This should work, too!
}
};
int main()
{
FunctionMap<F> fmap; // using the base template class directly works
fmap.registerFunction("f", f);
F fun = fmap.getFunction("f");
cout << fun(10) << endl;
return 0;
}