Cast unresolved template overloaded class member - c++

I have a class with two overloaded members. One takes an integer, the other one is a template function taking one argument.
class MyClass
{
public:
void doSomething(int data){ std::cerr << data;}
template <typename T> doSomething(T &&data){ std::cerr << data;}
};
I want to bind this function
MyClass myobject;
auto my_bind = std::bind(&MyClass::doSomething, &myobject, 2);
my_bind();
But this doesn't compile since the compiler cannot deduct which function to call.
error: no matching function for call to 'bind(unresolved overloaded function type, MyClass*, int)'
I understand that I have to cast the function.
auto my_bind2 = std::bind(static_cast<void (MyClass::*)(int)>(&MyClass::doSomething), &myobject, 2);
And now it compiles and works as expected.
But what if I want to bind it with any other parameter to call the template function? Is this even possible? I cannot find the syntax.
This doesn't work:
auto my_bind3 = std::bind(static_cast<void (MyClass::*)(std::string)>(&MyClass::doSomething), &myobject, std::string("Hello"));
I would like to avoid using lambdas. I simplified the code for MCVE but in the actual code I am supposed to use member pointers.
Thank you for the help

You should simply provide the address of a relevant instantiation of the member function-template:
auto my_bind3 = std::bind(&MyClass::doSomething<std::string&>, &myobject, std::string("Hello"));
//Note the reference here ^^
The above works because std::bind copies its arguments, and since the doSomething member function template takes its argument by a forwarding reference, we need to take advantage of reference collapsing.
While something like the snippet below will "bind",
auto my_bind3 = std::bind(&MyClass::doSomething<std::string>, &myobject, std::string("Hello"));
//Note the absence of a reference here ^^
It is going to fail when you eventually call my_bind3().
Demo
If you can use a lambda, use it, because perfect forwading will kick in.
auto my_bind4 = [&myobject](){ myobject.doSomething(std::string("\nHullo")); };

Related

no matching function call when using lambda function as an argument of a template function

I defined a class that receives an lambda function through constructor. The code is as follows. Why did the definition of t0 pass compilation after using the std::forward, and t1 incur an error?
#include <iostream>
template <typename Func>
class Test {
public:
Test(Func &&func) : m_func(std::forward<Func &&>(func)) {}
void Run() { m_func(); }
private:
Func &&m_func;
};
template <typename Func>
class Foo {
public:
Foo(Func &func) : m_func(func) {}
void Run() { m_func(); }
private:
Func &m_func;
};
int main() {
const auto print = []() { std::cout << "Hello" << std::endl; };
using Print = decltype(print);
Test<decltype(print)> t0(std::forward<Print&&>(print));
t0.Run();
Test<void()> t1(Print{});
t1.Run();
Foo<decltype(print)> t3(std::forward<Print&&>(print));
t3.Run();
Foo<void()> t4(Print{});
t4.Run();
}
[Update]
The definition of t1 should be as following. thx for #JaMiT.
Test<void(*)()> t1([]() { std::cout << "Hello" << std::endl; });
But I'm still confused about the definition of t0. If I deletes the std::forward, it incurs a compilation error.
[Update]
It works if I change the definition of t0 to Test<void (*)()> t0(print);. What's the difference between Test<decltype(print)> t0(print); that causes a compilation error?
Why did the definition of t0 pass compilation after using the std::forward,
Because that is how you declared the constructor of Test. The constructor takes as its parameter an rvalue reference to the template parameter. You explicitly provided decltype(print) as the template argument, so the constructor takes an rvalue of that type. There will be no copying (no pass by value), and an lvalue reference will not cut it. You must provide an rvalue.
By adding std::forward<Print&&>, you converted print to an rvalue. (It would have been simpler to add std::move instead. Rule of thumb: use std::forward when dealing with a "placeholder" type, such as a template parameter, and use std::move when dealing with a fixed type.)
Caution: After using std::forward<Print&&>(print) or std::move(print), you should treat print as uninitialized. That is, your initialization of t3 is a potential bug.
Another tweak that would make this compile is to specify decltype(print)& (with the ampersand at the end) as the template argument. When Func is an lvalue reference, Func&& collapses to Func, which means the constructor would take an lvalue reference instead of an rvalue reference. (Reference collapsing is a key component of forwarding references, on which perhaps you based your code? However, forwarding references would require the constructor to itself be a template.)
and t1 incur an error?
For t1, you specified the template argument as void(), which is the type of a function. Lambdas are objects, not functions, so there is a type mismatch.
On the other hand, a lambda with no captures (nothing inside the []) can implicitly convert to a pointer to a function. This is a place where confusion lurks, because functions also decay to pointers so people can get used to interchanging function types and pointer to function types. To specify a pointer to a function, use void(*)() instead of void().
Caution: Implicit conversions can wreak havoc when combined with references. Then again, you were already in the danger zone when you combined temporary objects (Print{}) with references. Your code would be safer if you changed the data member to Func m_func;. In addition to avoiding dangling references, this would be more efficient (less indirection) when storing a pointer-to-function.
template <typename Func>
class Test {
public:
// Constructor can still take a reference and forward it to the member.
Test(Func &&func) : m_func(std::forward<Func &&>(func)) {}
void Run() { m_func(); }
private:
Func m_func; // Not necessarily a reference
};
There are still potential issues (e.g. Func could be specified as a reference type), but at least this is safer. I choose to treat the remaining issues as out-of-scope for this question about syntax.
It works if I change the definition of t0 to Test<void (*)()> t0(print);.
This combines some concepts I presented earlier. The template argument is now a pointer to a function, so your lambda (print) will undergo an implicit conversion, similar to the t1 case. The result of an implicit conversion is an rvalue, which is what your constructor expects (no need to forward or move).
Caution: By "works", you really mean "compiles". The fact that you asked this question suggests you already know the following, but for the benefit of others: getting code to compile is a necessary step, but that by itself does not mean the code is correct and works as intended. Don't be satisfied when a tweak you do not understand makes your code compile – ask questions!

c++ template parameter compiler can not deduce

here is function to register.
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, std::function<int(int, const ReqT&, RespT&)> sync_handler) {
// ... do something with sync_handler and register it for later callback
return true;
}
and a specific handler to register:
int SomeHandler(int id, const Foo& req, Bar& resp) {
// ... specific logic
}
now I want to apply the Handler to Register Function, compiler complains
RegisterCmdHandler(1, SomeHandler); // ERROR, compiler can not deduce
while specificly write out the type is OK:
RegisterCmdHandler<Foo, Bar>(1, SomeHandler); // OK, compiler can deduce
but the latter has ugly API. How can I get the first on work?
How can I get the first on work?
Add an overload for plain function pointers:
template <typename ReqT, typename RespT>
bool RegisterCmdHandler(int cmd_id, int(*sync_handler)(int, const ReqT&, RespT&)) {
std::function<int(int, const ReqT&, RespT&)> sync_handler2(sync_handler);
return RegisterCmdHandler(cmd_id, sync_handler2);
}
How can I get the first on work?
I see some ways.
(1) If you can modify the RegisterCmdHandler() function and you don't need to know, inside it, what types ReqT and RestT are, I suggest you to avoid at all std::function and accept sync_handler as a simple template type.
I mean
template <typename F>
bool RegisterCmdHandler (int cmd_id, F sync_handler) {
// ... do something with sync_handler
return true;
}
This is a very flexible solution because F can be a function, a function pointer, a std::function, a lambda (also a generic lambda, so this solution is more flexible than using std::function), another type of class/struct with an operator(), a value returned from a std::bind. In short: a generic callable.
(2) If you can modify the RegisterCmdHandler() function but you need to know (and use) the ReqT and RestT, you can follows the plain function pointer way (see Maxim Egorushkin's answer for the syntax). Unfortunately this works with function pointers only and doesn't works (by example) when sync_handler is a lambda.
(3) If you can't modify RegisterCmdHandler() but you can use C++17, you can use std::function deduction guides and call the function as follows
RegisterCmdHandler(1, std::function{SomeHandler});
or, maybe better if you have to call it in different places, call it through a converter
template <typename F>
auto CallRegisterCH (int cmd_if, F && func)
{ return RegisterCmdHandler(cmd_if, std::function{std::forward<F>(func)}); }
calling it as follows
CallRegisterCH(1, SomeHandler);
(4) if you can't modify RegisterCmdHandler() and you have to use C++11 or C++14... well... explicating the template types
RegisterCmdHandler<Foo, Bar>(1, SomeHandler);
seems to me the better way.
Other ways you can explicit the std::function
std::function<int(int, Foo const &, Bar &)> sh{ SomeHandler };
RegisterCmdHandler(1, sh);
but seems to me almost the same thing.

std::function const correctness not followed

I was surprised to find this code compiles:
#include <functional>
struct Callable {
void operator() () { count++; }
void operator() () const = delete;
int count = 0;
};
int main() {
const Callable counter;
// counter(); //error: use of deleted function 'void Callable::operator()() const'
std::function<void(void)> f = counter;
f();
const auto cf = f;
cf();
}
https://wandbox.org/permlink/FH3PoiYewklxmiXl
This will call the non-const call operator of Callable. Comparatively, if you do const auto cf = counter; cf(); then it errors out as expected. So, why does const correctness not seem to be followed with std::function?
std::function adds a layer of indirection, and this layer of indirection does not pass through constness to the callable.
I'm not really sure why this is — probably because std::function takes a copy of the callable and has no need to keep the copy const (in fact this might break assignment semantics) — I'm also not really sure why you'd need it to.
(Of course, directly invoking operator() on an object of a type that you just so happened to call Callable and declared as const will require a const context, as it would with any other object.)
Best practice is to give the callable a const operator() and leave it at that.
tl;dr: true, but not a bug, and doesn't matter
You are correct to find this weird. The call operator of std::function is marked const but the constness is not propagated when the target object is actually invoked. The proposal p0045r1 seems to remedy this by making the call operator of std::function non-const but allowing the following syntax:
std::function<return_type(arg_type) const>
The reason is that assigning counter to std::function object creates a copy of counter.
In your case, f is initialized using the following constructor:
template< class F >
function( F f );
As described here, this constructor "initializes the target with std::move(f)" - a new object of type Callable is created and initialized using copy constructor.
If you'd like to initialize f with a reference to counter instead, you can use std::ref:
std::function<void()> f = std::ref(counter);
std::ref returns an instance of std::reference_wrapper, which has operator (), which calls Callable's operator () const. As expected, you'll get an error, since that operator is deleted.

C++ Bind Return Type Template Arguments

I have the following piece of code:
#include <functional>
template <typename T>
class TD; // For displaying type
void f(int, int, int) { }
int main() {
auto g = std::bind(f, std::placeholders::_1, 2, 2);
TD<decltype(g)> td1;
return 0;
}
In this code TD is a template trick for showing its template argument passed via decltype.
Output of the compiler follows (compiled in C++14 mode):
prog.cpp: In function 'int main()':
prog.cpp:10:18: error: aggregate 'TD<std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)> > td1' has incomplete type and cannot be defined
TD<decltype(g)> td1;
^
Well, incomplete type error is of course excepted. But what makes me curious in this error message is std::_Bind<void (*(std::_Placeholder<1>, int, int))(int, int, int)>. I can comprehend that std::_Bind is a proxy class which defines operator() and makes our purpose possible. But its template argument void (*(std::_Placeholder<1>, int, int))(int, int, int) made me woow! How should I interpret it? Does it have any usefulness in user-land code? How can I create my own classes making use of this declaration?
void (*(std::_Placeholder<1>, int, int))(int, int, int)
This declares an unnamed function taking three parameters (std::_Placeholder<1>, int and int) and returning a pointer to a function that takes three ints and returns void.
Let's simplify a little. First consider a simple function declaration:
void f(int)
Now, in parameter declarations (of functions or templates) you can omit the name and you get
void (int)
which, if used in a parameter list of a function declaration, would be equivalent to a function pointer void(*)(int).
A function that returns a function pointer is declared like this:
void (*f(int))(int);
// ^ ^ <- this pair of parentheses changes
// the order in which the declaration is parsed.
// Without it, the return type would be `void*`
// and you'd get a syntax error
Now you can remove the name f and you basically get the same thing that you were asking about.
Its uses? Apparently it's useful when implementing std::bind :) I can't think of anything else right now...
C++11 marked the advent of function which made defining function pointers far easier:
Instances of std::function can store, copy, and invoke any Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
So for example let's say that you needed to take in a function pointer to string foo(int param) { return to_string(param); } in one of your functions. Pre-C++11, your function would need to look like:
void bar(string (*func)(int)) { cout << func(13) << endl; }
Let's go a step further and say you wanted to expand foo to: string foo2(int lhs, int rhs) { return to_string(lhs + rhs); }. But now you want to cram that back into bar. Doing this bar(bind(&foo2, placeholders::_1, 42)); would give you an error like this:
cannot convert 'std::_Bind_helper (*)(int, int), const std::_Placeholder<1>&, int>::type {aka std::_Bind (*(std::_Placeholder<1>, int))(int, int)>}' to 'std::string (*)(int) {aka std::basic_string (*)(int)}' for argument '1' to 'void bar(std::string (*)(int))'
You could get around this error by creating a function that took an implementation specific argument, like: void bar2(_Bind<string (*(_Placeholder<1>, int))(int, int)> func) { cout << func(13) << endl; } which could successfully be called with: bar2(bind(&foo2, placeholders::_1, 42));. The reason that this is implementation specific is that the types: _Bind and _Placeholder are non-standard. In fact the return of bind is:
A function object of unspecified type T
Which brings us to function. If you weren't already turned off by the syntax the limitations of a function pointer, you'll need to take a function parameter to accept an object created by bind. Let's make a new bar using function:
void bar3(function<string(int)> func) { cout << func(13) << endl; }
This is capable of accepting both the traditional function pointer and the bind functor. Additionally it can handle lambdas, so you can do this: bar3([](int param) { return to_string(param); });
I've created a live example so you can play around with this some hopefully the benefits of the function object are clear.

What does reference with a template type mean?

In the code that I try to understand I see constructs like this: ref<date>(entry). Can anybody, please, explain what it can mean.
I assume that we create a reference to the entry object but how date type is used. For example ref<date>(entry) and ref<location>(entry) will return different values. How does it work?
If you have using namespace std; and are including the <functional> header, this is referring to the std::ref function.
std::ref is a function that will create a std::reference_wrapper wrapping the object you pass. The whole point of std::ref is that you don't have to give the template argument because it can be deduced. So if you want a reference to entry, then you should just do:
std::ref(entry)
It's a convenience function that saves you having to type redundant type names when creating a std::reference_wrapper. If you do it manually, you would have to do:
std::reference_wrapper<date>(entry)
That's because std::reference_wrapper is a template class and template class parameters cannot be deduced in this way.
The std::ref function template is used to create an std::reference_wrapper for a certain object. This allows passing an object by reference to a function template even though the function template takes the corresponding argument by value:
For instance:
template<typename T>
void foo(T t)
{
t = 42;
}
int x = 0;
foo(std::ref(x));
std::cout << x; // Will print 42
Notice, that function foo() above is quite a stupid function, and I wrote it just for illustrative purpose. More often, you will find std::ref or std::cref being used in combination with std::bind, which by default creates a copy of the arguments you provide:
template<typename T>
void bar(T v1, T& v2)
// ^
// Second argument accepted by reference this time...
{
v2 = v1 + 42;
}
int x = 0;
auto f = std::bind(bar, 0, ref(x));
// ^^^
// ...but without this, a copy of x would be created!
f(x);
std::cout << x; // Will print 42
Also notice, that you do not normally specify a template argument explicitly for std::ref or std::cref, but you rather let the function template deduce it.