Problem converting member function pointer to std::function with CRTP - c++

I am trying to pass a bound member function as an std::function while hiding the std::bind_front invocation in a base class. Minimal example:
#include <functional>
static void runIt(std::function<void()> f) { f(); }
template<typename T>
struct Base {
using PFn = void (T::*)();
void run(PFn fun) { runIt(std::bind_front(fun, this)); }
};
struct Derived : Base<Derived> {
void main() { run(&Derived::func); }
void func() {}
};
Unfortunately, the compiler does not like it:
static void runIt(std::function<void()> f)
No matching function for call to 'runIt' clang(ovl_no_viable_function_in_call)
test.cpp(12, 19): In instantiation of member function 'Base<Derived>::run' requested here
test.cpp(3, 13): Candidate function not viable: no known conversion from 'std::__perfect_forward_impl<std::__bind_front_op, std::__tuple_types<void (Derived::*)(), Base<Derived> *>, std::__tuple_indices<0, 1>>' to 'std::function<void ()>' for 1st argument
What am I missing?

You can't std::invoke(fun, this) since this is of type Base<Derived>* and the function pointer is of type void (Derived::*)() (And Derived is not a base of Base<Derived>, but the other way around).
Either upcast the pointer to member function or the pointer to the object. Preferably the object pointer:
runIt(std::bind_front(fun, static_cast<T*>(this)));

Related

Initialization of std::array with function pointer member function of constexpr object

I am trying to initialize an std::array of function pointers. These pointers point to member functions of an already instantiated object.
Can somebody please help with the following example? Many thanks in advance!
#include <array>
using TVoidVoid = void (*)(void);
class Foo {
public:
constexpr Foo() {}
void myHandler() {}
};
class Bar {
public:
constexpr Bar() : handler_{nullptr} {}
constexpr Bar(TVoidVoid handler) : handler_{handler} {}
private:
TVoidVoid handler_;
};
Foo f;
std::array<Bar, 5> bar_array = {{Bar{}, Bar{f.myHandler}}};
int main() {}
compiling produces:
main.cpp:22:56: error: no matching function for call to ‘Bar::Bar(<brace-enclosed initializer list>)’
std::array<Bar, 5> bar_array = {{Bar{}, Bar{f.myHandler}}};
I am using g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0.
Pointers to free functions are handled differently than pointers to member functions. The TVoidVoid type is a pointer to a free function, but you need a pointer to a Foo member function. Hence, define Foo first,
class Foo { /* As before... */ };
then go with a type alias for the member function (Foo must be known at this point)
// Note the different syntax to the former TVoidVoid
using FooVoidVoid = void (Foo::*)();
Next, Bar must be adjusted such that its data member is of type FooVoidVoid and the constructor accepts this type as an argument (the rest of Bar can be left as it is), and finally defined the array as
std::array<Bar, 3> bar_array = {{Bar{}, Bar{&Foo::myHandler}}};
Note that &Foo::myHandler has nothing to do with any existing Foo instance. It's just a pointer to a Foo member function, and only when you invoke it, this must be brought together with a Foo object (the special operators .* and ->* are meant for this to happen, or use std::invoke once you upgrade to a C++17-enabled compiler).

How to inherit some candidates of polymorphic function?

I want to define a function in a base class and a function with the same name and another signature in a subclass like this:
class A {
public:
void foo () {}
};
class B : public A {
public:
void foo(int x) {}
};
int main() {
B b;
b.foo();
}
But it causes compile error: no matching function for call to ‘B::foo()’.
If I comment foo definition in class B, it compiles.
How to solve the problem?
What I really want is to define a polymorhic interface in a base class and redefine semantic in child classes.
UPD: Thanks, the answers worked for this example. But it doesn't seem to work with templates:
sort.h
...
class Sort {
public:
template <typename TArr>
static TArr& sort(TArr& array) { return sort(array, array.size()); }
};
class BubbleSort : public Sort { // add inheritance
public:
using Sort::sort;
template <typename TArr>
static TArr& sort(TArr& array, size_t len) {
...
}
};
test.cpp
...
int main () {
...
std::array<int, 5> test_array {3, 2, 5, 1, 4};
BubbleSort::sort(test_array)
...
}
When I run this, I get:
sort.h: In instantiation of ‘static TArr& Sort::sort(TArr&) [with TArr = std::array<int, 5ul>]’:
test.cpp:9:30: required from here
sort.h:17:47: error: no matching function for call to ‘Sort::sort(std::array<int, 5ul>&, std::array<int, 5ul>::size_type)’
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: candidate: template<class TArr> static TArr& Sort::sort(TArr&)
static TArr& sort(TArr& array) { return sort(array, array.size()); }
^
sort.h:17:16: note: template argument deduction/substitution failed:
sort.h:17:47: note: candidate expects 1 argument, 2 provided
static TArr& sort(TArr& array) { return sort(array, array.size()); }
Why does it happen?
UPD: Got that.
Without virtual, the A::foo() doesn't define a polymorphic interface.
Anyway, you can make A::foo() visible via B with a using declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
This provides polymorphism to the extent that you accept function overloading as polymorphism--i.e., A::foo() and B::foo() form an overload set, and the compiler chooses which to call based on the parameter(s) you pass (if any), the same way as if B contained two overloaded functions (with the same signatures as the existing A::foo and B::foo).
But it causes compile error: no matching function for call to ‘B::foo()’
Try using-declaration:
class A {
public:
void foo() {}
};
class B : public A {
public:
using A::foo;
void foo(int x) {}
};
What I really want is to define a polymorphic interface in a base class and redefine semantic in child classes.
Well, you should make the base class function virtual an have the same parameters when override it. Otherwise, how the subclass function is supposed to be called via a reference/pointer to the base class?
Function f from the derived class simply hides all the functions with the same name from the base class.
To solve it you can use a using-declaration:
class B : public A {
public:
using A::foo;
void foo(int x) {}
};

Pointer to Member Function in Class Composition

I have two classes, Foo and Bar. Class Foo contains an instance of class Bar called b and class Bar needs to access the member function FooFunc of class Foo. Function FooFunc performs some arithmetic, but for now I just want to try to pass it but I can't seem to make the following MWE (named scratch.cpp) work:
#include <iostream>
class Foo; // forward declaration
class Bar
{
public:
Bar() {}
void BarFunc(double (Foo::*func)(double))
{
std::cout << "In BarFunc \n";
}
};
class Foo // must be declared after Bar, else incomplete type
{
public:
Foo() {}
Bar b;
double FooFunc(double x)
{
return x + 1;
}
void CallBarFunc()
{
b.BarFunc(FooFunc); // error occurs here
}
};
int main()
{
Foo f;
f.CallBarFunc();
}
The error I get is
scratch.cpp:27:22: error: no matching function for call to ‘Bar::BarFunc(<unresolved overloaded function type>)’
scratch.cpp:27:22: note: candidate is:
scratch.cpp:9:8: note: void Bar::BarFunc(double (Foo::*)(double))
scratch.cpp:9:8: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘double (Foo::*)(double)’
Unlike non-member functions, which decay to a function pointer, non-static member functions don't decay to a pointer.
Instead of:
b.BarFunc(FooFunc);
Use:
b.BarFunc(&Foo::FooFunc);

Why do function pointers break substitutability and std::function doesn't?

We have an usual class hierarchy:
class B
{
public:
int x;
B() : x(0) {}
virtual ~B() {}
};
class D : public B
{
public:
int y;
D() : y(0) {}
};
And a function that takes one argument - reference to a base class object.
void b_set(B& b)
{
b.x = 5;
}
Then, I want to create function pointer of type void (D&) and store b_set in it. This should be valid operation, as all objects legally passed to function pointer call must be also of type B. Yet it isn't allowed.
typedef void (*fp_d_mutator)(D&);
void fp_test(D& obj)
{
fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)}
fun(obj);
}
#include <functional>
typedef std::function<void (D&)> stdfun_d_mutator;
void stdfun_test(D& obj)
{
stdfun_d_mutator fun = b_set; //works
fun(obj);
}
So...
How is that invalid conversion?
Why is that invalid conversion?
What could break if this was allowed?
How std::function avoids the problem in the first place?
A function that takes an argument of type B& is not a function that takes an argument of type D&. While D& is convertible to B&, they are not the same type. If you could store a pointer to a function that takes B& as a pointer to D&, how would the compiler know when to convert the argument? (Note that the conversion sometimes requires adjusting a pointer)
The difference in std::function is that the calling signature (here D&) is part of the function object's type, and the called signature (here B&) is part of the internal storage. So when you apply the function objects' operator() the code that implements operator()(D&) takes care of the conversion.

Member function pointer to function object

I have a class with a function pointer as a member. In a certain case I would like that pointer to point to a function object, is that not possible?
class C {
public:
C();
private:
void (*p)();
struct Functor {
void operator()() {
}
};
};
C::C() : p(Functor()) {
}
int main(int argc, char **argv) {
C c;
}
I get:
t.cpp: In constructor 'C::C()':
Line 12: error: cannot convert 'C::Functor' to 'void (*)()' in initialization
No, it is not possible. The type of Functor is not even close to the type void(*)(). You can either change the member p to be of type Functor, or what you may be looking for is std::function:
std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any callable target -- functions, lambda expressions, bind expressions, or other function objects.
No, a Functor object is not a function pointer. If you would like to initialize p as a Functor, you should declare it as such:
class C {
public:
C();
private:
struct Functor {
void operator()() {
}
} p;
};