Templated method pointer - can't match pointer for function argument - c++

I am making a method pointer wrapper like this:
template<typename OBJECT, typename... ARGS>
method_wrapper<ARGS...> _getWrapper(OBJECT* object, void (OBJECT::*method)(ARGS...))
{
//irrelevant
}
The problem is right at the calling of _getWrapper:
class TestClass
{
void TestMethod(int a, float b, bool c)
{
std::cout<<a<<std::endl;
std::cout<<b<<std::endl;
std::cout<<c<<std::endl;
}
};
int main()
{
TestClass testObj;
method_wrapper<int, float, bool> wrap = _getWrapper<int, float, bool>(&testObj, TestClass::TestMethod);
wrap.callInternal(1000, 3.14, true);
//...
system("pause");
return 0;
}
Not matter in what way I try to pass the arguments in _getWrapper, it still tells me:
no instance of overloaded function matches the argument list
Doesn't OBJECT::*method match TestClass::TestMethod directly? I also tried &TestClass::TestMethod, doesn't match either.

You're specifying the template arguments explicitly when invoking _getWrapper, and the first one is specifed as int for template parameter OBJECT, which is wrong. Because member pointers can't refer into non-class type.
Change
_getWrapper<int, float, bool>(&testObj, TestClass::TestMethod)
to
_getWrapper<TestClass, int, float, bool>(&testObj, &TestClass::TestMethod)
// ~~~~~~~~~~
Note you can just rely on template type deduction, e.g.
_getWrapper(&testObj, &TestClass::TestMethod)
BTW: For taking address from members you should always use & for it.
BTW: I suppose TestClass::TestMethod is public.

Related

Passing Function Type As Template Parameter Does Not Compile

So I have a class that takes two template parameters, one is the type, one is the type of the function used, it has a reduce function to apply this function repeatedly to the array. However, I'm getting a compilation error.
function_template_test.cpp: In instantiation of 'class _C<int, int(int, int)>':
function_template_test.cpp:36:33: required from here
function_template_test.cpp:11:17: error: field '_C<int, int(int, int)>::op' invalidly declared function type
BinaryOperator op;
Here is my code. I have a class and the driver code down below in the main method.
#include<iostream>
template<typename _T>
_T addition(_T x,_T y)
{
return x+y;
}
template<typename _T,typename BinaryOperator>
class _C
{
private:
BinaryOperator op;
public:
_C(BinaryOperator op)
{
this->op=op;
}
_T reduce(_T*begin,_T*end)
{
_T _t_=*begin;
++begin;
while(begin!=end)
{
_t_=this->op(_t_,*begin);
++begin;
}
return _t_;
}
_T operator()(_T*begin,_T*end)
{
return this->reduce(begin,end);
}
};
int main(int argl,char**argv)
{
int arr[]={1,4,5,2,9,3,6,8,7};
_C<int,decltype(addition<int>)>_c_=_C<int,decltype(addition<int>)>(addition<int>);
std::cout<<_c_(arr,arr+9)<<std::endl;
return 0;
}
You're specifying function type as the template argument for BinaryOperator, which can't be used as the data member op's type; you can specifty function pointer type instead. e.g.
_C<int,decltype(addition<int>)*>_c_=_C<int,decltype(addition<int>)*>(addition<int>);
// ^ ^
BTW: Names like _C beginning with an underscore are reserved in C++.
Normally when assigning a function to a function pointer you don't explicitly need to add the address of operator (&) as it is not valid to assign the function itself to a variable so the language automatically adds it for you. However when doing decltype on a function name you do get the function type not a function pointer. For example try compiling the following, all the static_asserts should pass:
#include <type_traits>
void foo() {}
int main()
{
auto a = foo;
auto b = &foo;
static_assert(std::is_same_v<decltype(a), decltype(b)>,"a and b are function pointers");
static_assert(!std::is_same_v<decltype(a), decltype(foo)>,"foo is not a function pointer");
static_assert(std::is_same_v<decltype(a), decltype(&foo)>,"&foo is a function pointer");
}
Your code is essentially equivalent to:
#include <type_traits>
void foo() {}
int main()
{
decltype(foo) c = foo;
}
Which doesn't compile. Changing it to this fixes the problem:
#include <type_traits>
void foo() {}
int main()
{
decltype(&foo) c = foo;
}
The fix to your code is to change it to:
_C<int,decltype(&addition<int>)>_c_=_C<int,decltype(&addition<int>)>(addition<int>);
Or you can avoid repeating the types by just constructing directly:
_C<int,decltype(&addition<int>)>_c_(addition<int>);
Or using auto:
auto _c_=_C<int,decltype(&addition<int>)>(addition<int>);

Trying to push_back into a vector pointing to an abstract class

Compiling my code that contains this class:
class Dessin
{
private:
vector<Figures*>T;
public:
void ajouteFigure(const Figures& f) const
{
for(auto element: T)
{
T.push_back(f);
}
}
};
yields an error:
[Error] no matching function for call to
'std::vector::push_back(const Figures&) const'
This is what I'm supposed to do in the main()
Dessin s;
s.ajouteFigure(Cercle(1.1));
Why wouldn't this work?
Assuming Cercle is a class name, you're trying to push a value where a pointer is expected.
To "fix" the error you should change your ajouteFigure prototype to accept Figures pointers and non-const this:
void ajouteFigure(Figures* f)
Then you should call it passing a pointer to a Figures object, i.e. created with a new expression:
s.ajouteFigure(new Cercle(1.1));
That being said, this code seems pointless. You're adding the pointer as many times as you have elements in the vector (which is always 0 in the example you provided).
Using raw pointers is also unadvised, you should use smart pointers like std::unique_ptr, although that would break the current code.
Consider this, less improper, example:
class Dessin
{
private:
vector<unique_ptr<Figures>> T;
public:
void ajouteFigure(unique_ptr<Figures> f)
{
T.push_back(move(f)); // just once
}
};
and at the call site:
Dessin s;
s.ajouteFigure(make_unique<Cercle>(1.1)); // C++≥14
or, if you can't use C++14:
Dessin s;
s.ajouteFigure(unique_ptr<Figures>(new Cercle{1.1}));
Just to add to this, I think you would be better to make it a template function and create the right object inside the function with arguments to the constructor passed as function parameters.
This way you don't have to create a std::unique_ptr or use new every time you call the function.
Here's a basic implementation:
class Dessin{
public:
template<typename T, typename ... Args>
void ajouteFigure(Args &&... args){
figures.emplace_back(new T(std::forward<Args>(args)...));
}
private:
std::vector<std::unique_ptr<Figures>> figures;
};
Then using the class is less error-prone:
int main(){
Dessin d;
d.ajouteFigure<Cercle>(1.1);
}

Pointer to the method / passing this pointer / boost::bind

I'm wondering how "this" pointer is being passed to the methods from the class.
Let's see this snippet of code:
class CTest
{
public:
CTest(int n_) : n(n_) {}
void method()
{
std::cout << n << std::endl;
}
private:
int n;
};
int main()
{
CTest t1(100);
boost::bind(&CTest::method, &t1)(); //100
boost::bind(&CTest::method, _1)(&t1); //100
Test::method(&t1); //no matching function for call to ‘CTest::method(CTest*)’
return 0;
}
Assuming the bind works just like a function object, it passes this/object pointer somehow. If I want to do it explicitly I get an compilation error.
How does it work in fact?
boost::bind recognises when the target it wraps is a pointer to member, and uses a different code path that calls it using the right syntax for a pointer to member.
Like most problems in programming, you can solve it by adding a level of indirection. bind can apply a transformation to its target so that a pointer to member will be adapted into something that can be called like a normal function object, and takes care of the details, so bind itself doesn't need to know the details.
The function boost::mem_fn can be used to transform a pointer to member into a callable object:
void (CTest::*memptr)() = &CTest::method;
CTest* p = &t1;
auto callable = boost::mem_fn(memptr);
callable(p); // calls (p.->*memptr)()
So given that adaptor, bind only needs to ensure it is used whenever needed.
In the GCC implementation we have something like this:
template<class T>
struct maybe_wrap_mem_ptr
{
typedef T type;
};
// partial specialization for pointer to member
template<class R, class C>
struct maybe_wrap_mem_ptr<R C::*>
{
typedef mem_fn_wrapper<R C::*> type;
};
template<class T>
typename maybe_wrap_mem_ptr<T>::type
wrap_mem_ptr(T t)
{ return typename maybe_wrap_mem_ptr<T>::type(t); }
Where mem_fn_wrapper is the type returned by the std::mem_fn function. So bind can just use wrap_mem_ptr to ensure that the object it wraps can be called uniformly.

Function pointer and Template

Why does the following code work?
class foo {
public:
template <typename F>
int Map(F function) const {
return function(2);
}
};
int Double(int n) {
return 2*n;
}
int main(){
foo f;
int n = f.Map(Double);
}
My understanding is that the function accepting the function pointer must have format such as:
void foo(int (*ptf)(int))
So the Map function should look like
int Map(int (*ptf)(int)){
return (*ptf)(2);
}
does the it somehow resolve the function at run-time or at compile-time through template?
the above code was compiled and ran in vc++ 2010
Template are a compile-time concept, so of course it will be resolved during compile time (if what you mean is the template parameter substitution). Try passing something which you can't call like function(2), e.g., some int. This will yield a compile-time error. After substitution, your function will look like
int Map(int (*function)(int)){
return function(2);
}
You don't explicitly need to dereference a function pointer, because both function(2) and (*function)(2) are immediatly converted to a so-called function designator. That itself is dereferenceable again and you can build an endless chain: (***********function)(2) will still work and is still the same as function(2) and (*function)(2).

Pointers to functions

I have to pass function into pointer. For this purposes I'm using boost::function. The function which catches the pointer is overloaded for different signatures. For example:
void Foo(boost::function<int ()>) { ... }
void Foo(boost::function<float ()>) { ... }
void Foo(boost::function<double ()>) { ... }
Now I wanna pass some class-method pointer there:
class test
{
public:
float toCall() { };
};
class Wrapper
{
Wrapper() {
test obj;
Foo(boost::bind(&test::toCall, this));
}
};
error: no matching function for call to ‘Foo(boost::_bi::bind_t<float, boost::_mfi::mf0<float, test>, boost::_bi::list1<boost::_bi::value<Wrapper*> > >)’
note: candidates are: Foo(boost::function<float()>&)
Nonono this cannot work. Because boost::function<...> has a templated constructor to accept any and all types. Compatibility with the call signature is checked later on. Overload resolution cannot resolve this.
Also, i think you want to pass &obj instead of this. Try converting explicitly:
Foo(boost::function<float ()>(boost::bind(&test::toCall, &obj)));
This is utterly ugly though so you may want to introduce a typedef
void Foo(FloatHandler) { ... }
...
FloatHandler f(boost::bind(&test::toCall, &obj));
Foo(f);
Or ultimately you could make Foo a template that accepts just any callable type T. I suspect that may be the simplest, because in the general case i suspect you don't know to what boost::function<...> you need to cast to. And how about folks that want to return a std::complex<>. So...
template<typename T>
void Foo(T) { ... }
...
Foo(boost::bind(&test::toCall, &obj));
Hope this helps.
In the line
Foo(boost::bind(&test::toCall, this));
this is of type Wrapper. But the bind can't find a toCall method on it.
Here's a fixed-up version (complete, compiles on g++ 4.3.2) which is probably what you're trying to do:
#include <boost/bind.hpp>
#include <boost/function.hpp>
void Foo(boost::function<int()>) {}
void Foo(boost::function<float()>) {}
void Foo(boost::function<double()>) {}
struct test {
float toCall() {return 0.0f;}
};
int main(int,char**) {
test obj;
boost::function<float()> tgt=boost::bind(&test::toCall,obj);
Foo(tgt);
return 0;
}
As AndreyT's answer notes, the return type of bind is... a bit odd, hence the explicit coercion to an appropriate function type.
boost::bind does not return a boost::function object. It returns an object of unspecified type that can be used as a functor with corresponding number of parameters.
While boost::function can be conversion-constructed from the result of boost::bind, the overload resolution in this case is "too complex" for C++. (Removed my bad example which didn't really illustrate the right problem).