Call a class's function template with function pointers as parameters - c++

I'd want to use a function pointer in my template argument list. I do miss something of B even I am writing int in full main of both A and B. I have a class X.h like so, don't know which one it is now causing the error.
struct X
{
int fun(int a)
{
return a;
}
template<typename A, typename B>
A func(int x, B(*f)(int))
{
A i = 10;
return i + f(x);
}
};
and I like to use it in main.cpp
int main()
{
X d;
std::cout << d.func<int, int>(10, &X::fun) << "\n";
return 0;
}
The error is No instance of func matches the argument list...

The problem is that the argument &X::fun is of type int (X::*)(int) while the parameter f is of type int(*)(int) (when B = int) and there is no implicit conversion from the former to the latter and hence the error.
To solve this you can change the parameter f to be of type B(X::*)(int) as shown below. Note that the syntax for making a call using member function pointer is different for making a call to a free function.
With C++17, we can use std::invoke.
struct X
{
int fun(int a)
{
return a;
}
template<typename A, typename B>
//------------------vvvv-------------->added this X:: here
A func(int x, B(X::*f)(int))
{
A i = 10;
//-----------------vvvvvvvvvv-------->this is the syntax to call using member function pointer
return i + (this->*f)(x);
//return std::invoke(f, this, x); //use std::invoke with C++17
}
};
int main()
{
X d;
std::cout << d.func<int, int>(10, &X::fun) << "\n"; //works now
return 0;
}
Working demo

Related

Can we write a function which returns a function pointer to a function template?

Is it possible to write a function or method which can return a pointer to a template function or template method?
Example:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
// static auto GetPtr() { return X1::Do; } // how to write such a function?
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
//static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic(true, X1::Do, X2::Do);
// should be replaced by:
// auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
If I compile the above out-commented functions, I got from gcc:
main.cpp:1845:39: error: unable to deduce 'auto' from 'X1::Do'
Background: I am currently trying to understand the overload resolution in same cases. In the given case you see that the overload for int is taken because one function pointer only has an int parameter so the second pointer overload can be found.
I was triggered by that question: Ternary operator applied to different lambdas produces inconsistent results
Here in an answer was suggested, that a lambda should be able to provide a conversion operator to a function pointer... and I did not see it :-)
The compiler doesn't "know" in advance all your uses for X1::GetPtr (generally). It seems you are expecting the compiler to 1. recognize it is a template 2. recognize all uses for the function, and see if it can deduce all instantiations needed for the template "for free", so to speak - in your case only the use in magic, but this is not general.
There is no such mechanism in C++ and the compiler must know the type of the function when it parses it, or recognize it as a template (and not guess it).
Simply put, I think you are expecting the compiler to do something too difficult, and it can't. As such, you will have to do the template resolution yourself:
template<typename N>
static auto GetPtr() { return &X1::Do<N>; }
and call it with
magic(true, X1::GetPtr<int>(), X2::GetPtr());
No you cannot return a pointer to a function template, because a function template is not a function. It is a template.
// static auto GetPtr() { return X1::Do; } // how to write such a function?
You need & to get a pointer to a member function, though Do is not a member function it is a member function template. You could return a pointer to X1::Do<int> or to X1::Do<double> but there is no pointer to X1::Do.
You can however return a functor with an overloaded call operator and that operator can be a template:
struct foo {
template <typename T>
void operator()(const T& t) {}
void operator()(int x){}
};
foo magic() { return foo{}; }
int main() {
magic()(3); // calls operator()(int)
magic()("hello world"); // calls operator()<const char[12]>
}
After rereading your question and the Q&A you link, I think you are maybe looking for this:
#include <iostream>
struct X1 {
static void Do(auto n) { std::cout << "1" << n << std::endl; }
static auto GetPtr() { return &X1::Do<int>; }
};
struct X2 {
static void Do(int n) { std::cout << "2" << n << std::endl; }
static auto GetPtr(){ return &Do; }
};
template <typename T> T magic(bool b, T t1, T t2) { return b ? t1 : t2; }
int main() {
auto l1 = magic( true, X1::GetPtr(), X2::GetPtr() );
l1(100);
}
As stated above, you cannot get a member function pointer to X1::Do but you can get a pointer to X1::Do<int>.
And as you are refering to conversion of lambdas to function pointers: Also lambdas with auto argument can only be converted to function pointers after choosing the argument type. Consider the example from cppreference:
void f1(int (*)(int)) {}
void f2(char (*)(int)) {}
void h(int (*)(int)) {} // #1
void h(char (*)(int)) {} // #2
auto glambda = [](auto a) { return a; };
f1(glambda); // OK
f2(glambda); // error: not convertible
h(glambda); // OK: calls #1 since #2 is not convertible
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
It is not possible to get a pointer to function of type auto(auto) (it isn't a type of a function to begin with). In all the calls above, after the conversion there is no auto anymore. Instead the requested type is deduced and a conversion to the respective function pointer is done.

C++ member function with auto and default arguments

I am trying to implement a member function in a C++ class which has an auto argument (a lambda) and an int argument with a default value. Something like this:
class Base {
public:
int add_one(auto fobj, int b=3);
};
int Base::add_one(auto add_fcn, int b) {
return add_fcn(1, b);
}
However, a simple test like this fails to compile:
#include <iostream>
class Base {
public:
int add_one(auto fobj, int b=3);
};
int Base::add_one(auto add_fcn, int b) {
return add_fcn(1, b);
}
int main() {
int ans;
auto add_fcn = [](int a, int b) -> int {return a + b;};
Base obj;
ans = obj.add_one(add_fcn);
std::cout << ans << "\n";
return 0;
}
The error the compiler (MinGW 7.2.0, flags: -std=c++14) gives me is the following:
error: call to 'int Base::add_one(auto:2, int) [with auto:1 = main()::<lambda(int, int)>]' uses the default argument for parameter 2, which is not yet defined
I sincerely do not understand the error. Can someone please explain me the reason of this error and how it can be fixed? Thank you in advance.
auto parameters is a gcc extension. It means that it is not a standard compliant way to solve the problem.
I am not sure what is the exact reason for the error above, but you might achieve the same effect with template member function which works well:
class Base {
public:
template<typename F>
int add_one(F fobj, int b = 3);
};
template<typename F>
int Base::add_one(F add_fcn, int b) {
return add_fcn(1, b);
}
Wandbox example
Another possible way is to use std::function (which implies some performance overhead though):
class Base {
public:
int add_one(std::function<int(int, int)> fobj, int b = 3);
};
int Base::add_one(std::function<int(int, int)> add_fcn, int b) {
return add_fcn(1, b);
}
Wandbox example
Finally, you could make use of pointers to functions, but it is too C way...
If you'd like to expand your knowledge on passing functions to functions, this article by Vittorio Romeo gives an excellent explanation + some benchmarks.

Using a custom constructor as a template function

I have template function change that takes a function that takes int and returns an object of type A. So I thought I can use the constructor of A
class A {
int y;
public:
explicit A(int y) : y(2 * y) {
}
};
class B {
A x;
public:
B(int x) : x(x) {
}
template<typename F>
void change(int y, F func) {
x = func(y);
}
};
int main(void) {
B b(7);
b.change(88, A()); // << here
return 0;
}
But the compiler says no matching function for call to ‘A::A()’
How can I make it works?
You can't pass a constructor as a parameter like you are attempting. The C++ standard is very strict on not allowing the memory address of a constructor to be taken.
When you call change(88, A()), you are actually constructing a temp A object (which the compiler should not allow since A does not have a default constructor) and then you are passing that object to the parameter of change(). The compiler is correct to complain, since A does not define an operator()(int) to satisfy the call to func(y) when called in an A object.
To make this work, you need to create a separate function that constructs the A object, and then pass that function to change(), eg:
A createA(int y)
{
return A(y);
}
int main(void) {
B b(7);
b.change(88, createA);
return 0;
}

Why can't decltype work with overloaded functions?

decltype fails if the function you're calling it on is overloaded, as in this code:
#include <iostream>
int test(double x, double y);
double test(int x, int y);
char test(char x, int y);
int main()
{
std::cout << decltype(test) << std::endl;
return 0;
}
Results:
error: decltype cannot resolve address of overloaded function
I understand that this is because decltype can't figure out which function you're trying to get the type of. But why isn't there another way to make this work, like this:
std::cout << decltype(test(double, double)) << std::endl;
or this:
double x = 5, y = 2;
std::cout << decltype(test(x, y)) << std::endl;
Since a function cannot be overloaded simply based on return type, wouldn't passing either datatypes or actual variables to the decltype call be enough to tell it which of the overloads it's supposed to examine? What am I missing here?
To figure out the type of the function from the type of the arguments you'd pass, you can "build" the return type by using decltype and "calling" it with those types, and then add on the parameter list to piece the entire type together.
template<typename... Ts>
using TestType = decltype(test(std::declval<Ts>()...))(Ts...);
Doing TestType<double, double> will result in the type int(double, double). You can find a full example here.
Alternatively, you might find the trailing return type syntax more readable:
template<typename... Ts>
using TestType = auto(Ts...) -> decltype(test(std::declval<Ts>()...));
I belive you may be looking for std::result_of<>
cppreference page.
I have found another way: use std::declval to generate a fake object, then use decltype:
#include <type_traits>
#include <functional>
int myfunc(int a)
{
return a;
}
float myfunc(float a)
{
return a;
}
int main()
{
decltype(myfunc(std::declval<float>())) a; // return type
std::function<decltype(a)(float)> fun; // function type
return 0;
}

passing a pointer to a class method as a function argument [duplicate]

This question already has answers here:
How do you pass a member function pointer?
(6 answers)
Closed 9 years ago.
I have a class
class A{
A(/*constructor arguments*/);
double MethA(double);
};
And I want to pass the method MethA in a function that takes a pointer to a function :
double function(double (*f)(double), double x){
return f(x);
}
So what I'm doing is to call
A a(/*constructor arguments*/);
function(a.MethA,1.0);
but it doesn't compile.
I'm pretty sure that this question is answered somewhere else, but I couldn't find where because I'm not sure that the terminology I use is correct. Am I trying to pass a pointer on a class method as a function argument ? Or, to pass a function pointer as a member of a class... I'm confused :-(
When you need to use a pointer to member function, you need to pass two separate things:
what member function to call and
what instance to call it on.
In C++, you can't combine them in one construct, like you want to:
A a;
bar(a.foo);
is not valid C++.
Instead, you have to do this:
A a;
bar(a, &A::foo)
And declare and implement bar() accordingly:
void bar(A &a, void (A::*method)()) {
a.*method();
}
See Arkadiy's answer if you want to see how to properly use member function pointers.
BUT
As requested in the comments: if the compiler you are using supports lambdas (some without full C++11 do). You can do something like the following, which looks more like the syntax you are attempting to use.
Your definition for function changes to something like:
template <typename F>
double function(F f, double x){
return f(x);
};
a function template that accepts a parameter that is callable with a double.
At your call-site you do this:
A a(/*constructor arguments*/);
function([&](double x){return a.MethA(x);},1.0);
That generates a function object in-place that is bound to your class instance a by reference.
The template can be made fully typesafe with some magic in <type_traits>, but as-is it will give you template spew if you pass something very wrong.
It has to be a static function!
#include <iostream>
#include <cassert>
class A {
public:
static double MethA(double x) { return 5 * x; }
};
typedef double (*ftype)(double);
double function(ftype f) {
assert(f != NULL);
return f(7);
}
int main(int, char**) {
// expect "35\n" on stdout
std::cout << function(A::MethA) << "\n";
}
It has to be static because you can't access any of A's variables without knowing which A object are you refering to! If you need A's non-static member variables, you need to pass a reference to an a into the static function:
#include <iostream>
#include <cassert>
class A {
double fX;
public:
A(double x) : fX(x) { }
double methB(double x) const { return fX * x; }
static double MethB(double x, const A& a) {
return a.methB(x);
}
};
typedef double (*ftype2)(double, const A&);
double function_with_context(ftype2 f, const A& a) {
assert(f != NULL);
return f(7, a);
}
int main(int, char**) {
A a(6);
// expect "42\n" on stdout
std::cout << function_with_context(A::MethB, a) << "\n";
}
But it's sometimes better to use inheritance and polymorphism to achieve this sort of interface:
#include <iostream>
class MyInterface {
public:
virtual double f(double x) const = 0;
};
class A : public MyInterface {
double fX;
public:
A(double x) : fX(x) { }
double f(double x) const {
return fX * x;
}
};
double function(const MyInterface& o) {
return o.f(7);
}
int main(int, char**) {
A a(6);
// expect "42\n" on stdout
std::cout << function(a) << "\n";
}