Let's say we have got a raw C-style string "test". We can declare a function like this:
void printText(std::string textToPrint){
std::cout << textToPrint << "\n";
}
and we may call it in a following manner:
printText("test");
And this should be perfectly fine, as argument is an object, not a reference, so temporary object like std::string("test") should be created in time of calling function `printText()'.
Now given that, I have a following template:
template <typename T>
T checkMe(Proxy<T> arg){
std::cout << arg() << std::endl;
return arg();
}
where Proxy class declaration is as follows:
template <typename T>
class Proxy{
public:
Proxy(std::function<T&()> caller);
Proxy(std::shared_ptr<T> dataPtr);
T& operator()();
private:
std::function<T&()> m_functional;
std::shared_ptr<T> m_data;
};
It's purpose is to make some of the functions be called with two object types:
One is shared_ptr to the data and another is functional object, that returns this type of data.
Now when I want to call function checkMe error happens, that I do not know why appears and how to solve it. One thing is:
getMe(std::make_shared<int>(255));
And this in my opinion should be perfectly fine, as Proxy's constructor takes shared_ptr as argument and creates itself based on it. But this gives compiler's deduction error. Whereas, when I call function like this:
getMe<int>(std::make_shared<int>(255));
Well now it's fine. I do not know why does compiler cannot deduce the type on it's own.
Second case is calling it with a functional object:
getMe<int>(std::bind(getNumberMult,5,6));
Where getNumberMult is defined as follows:
int xy;
int& getNumberMult(int x, int y){
return xy = x*y;
}
Here conversion error occurs. Could someone please specify is it possible and how to achieve desired behavior of the given code and explain what is wrong with my understanding of the mechanism? I would like to use this code as follows:
getMe(std::make_shared<int>(300));
getMe(std::bind(getNumberMult, 6, 7));
Compiler errors:
when using
getMe<int>(std::bind(getNumberMult, 5, 6));
path/to/file:36: error: C2664: 'T getMe<int>(DataProxy<T>)' : cannot convert argument 1 from 'std::_Bind<true,int &,int &(__cdecl *const )(int,int),int,int>' to 'DataProxy<int>'
with
[
T=int
]
With T checkMe(Proxy<T> arg), arg should be a Proxy<T> (or inherit from it).
Compiler doesn't check the infinite possibilities to test each Proxy<T> can be construct from given argument.
So generally I know now why it is so, and what should I do to fix it.
Consider following object:
struct Test{
Test(std::string someString){}
};
So we need std::string just for constructing object of this class.
We can do without std::string created explicitly in following manner:
int main(){
Test someVariable("someRawString");
}
It's gonna work and it is completely fine. What happens underhood is:
compiler meets instruction for creating object of Test class
It sees, that given argument is not of type required by Constructor
because of the fact, that required argument is a value, not a reference (const reference would also be fine) it creates temporary object of type std::string and passes this temporary object to the constructor
Object is successfully created.
Now let's consider function:
void someTestFunction(Test someTest){}
It requires object of type Test, that is constructed from std::string
Given that, it should be fine to invoke this function in following manner:
someTestFunction("someRawText");
But it's not fine. This gives us error of converting arguments. Reason for it is quite simple: C++ allows only one step of converting, when passing parameters to the function. So compiler can:
cast raw string to std::string
create Test object with std::string
But it cannot:
cast raw string to std::string
cast std::string to Test (too many conversions)
invoke function with Test
Exactly the same things happened with the given code. To make it work we should use:
getMe<int>(std::make_shared<int>(300));
getMe<int>(std::function<int&()>(std::bind(getNumberMult, 6, 7)));
Why is it so?
std::make_shared<int> has return type of std::shared_ptr<int>, so no conversion was required to invoke a function.
std::bind... has a returning type different than std::function, it has it's own implementation defined return type. That is why this second cast would be required here, which is not allowed by C++. When we cast it explicitly, then only one implicit cast is required and everything works fine.
Related
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!
I would like to pass function pointer as a function parameter.
Here is my code:
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode, void(*handlerFunc(std::vector<std::byte> data))) {}
Here is the function I would like to pass as second parameter in ValidateAndSetServerOpcode:
void AuthServerOpcodes::Test(std::vector<std::byte> data) {
std::cout << "all good" << std:end
}
Here is how I try to pass it:
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &Test);
However this seems to be not the correct way. When I try to do it in that way I get error:
Cannot initialize a parameter of type 'void (*(*)
(std::vector<std::byte>))' with an rvalue of type 'void
(AuthServerOpcodes::*)(std::vector<std::byte>)': different return type
('void (*)' vs 'void')
Why is that and how can I fix it?
Pointers to member must be qualified with the class type, so you need to get the pointer you'll need to use
ValidateAndSetServerOpcode(SMSG_LOGIN_REQUEST, &AuthServerOpcodes::Test);
But it looks like you've tried that in the previous edit, so I guess you've called the function pointer to member incorrectly. You didn't show a minimal, reproducible example so I can't help you more, please create one. Anyway I've created a compiled example on Compiler Explorer
typedef void (AuthServerOpcodes::*HandlerFunc)(std::vector<std::byte> &);
void AuthServerOpcodes::ValidateAndSetServerOpcode(ServerOpcode serverOpcode,
HandlerFunc handlerFunc)
{
std::vector<std::byte> myVector;
(this->*handlerFunc)(myVector); // call the hander
}
void FreeStandingFunction(AuthServerOpcodes& opc,
AuthServerOpcodes::HandlerFunc handlerFunc,
std::vector<std::byte> &data)
{
(opc.*handlerFunc)(data);
}
As you can see the pointer to member must be called with ->* or .* and the whole dereferencing must be wrapped inside () because those operators has lower precedence than the function call operator ()
See also Function pointer to member function
Some off-topic note:
Don't use lines that are too long like that
Don't pass vectors by values unless you really need to preserve the outside value. Always pass by reference with const std::vector<>& (or remove const to modify the outside variable)
Use '\n' instead of std::endl
You can't do that.
There is no function pointer to that function, because it is a member function.
You can instead pass a pointer-to-member-function, or better yet a std::function bound to a lambda that captures the this pointer.
It's just a type mismatch, your function is a method of the AccountManager class,
so it has this signature similar to:
static void Login(AccountManager *this, std::vector<..> data);
You can either detach function from class, change your type definition of handlerFunc or consider different techniques like std::mem_fn or std:bind
https://en.cppreference.com/w/cpp/utility/functional/mem_fn
https://en.cppreference.com/w/cpp/utility/functional/bind
I recently ran into a bug in my code when using boost::bind.
From the boost::bind docs:
The arguments that bind takes are copied and held internally by the returned function object.
I had assumed that the type of the copy that was being held was based on the signature of the function. However, it is actually based on the type of the value passed in.
In my case an implicit conversion was happening to convert the type used in the bind expression to the type received by the function. I was expecting this conversion to happen at the site of the bind, however it happens when the resulting function object is used.
In retrospect I should have been able to figure this out from the fact that using boost::bind gives errors when types are not compatible only at the call site, not the bind site.
My question is:
Why does boost::bind work this way?
It seems to give worse compiler error messages
It seems to be less efficient when implicit conversion happens and there are multiple calls to the functor
But given how well Boost is designed I'm guessing there is a reason. Was it behavior inherited from std::bind1st/bind2nd? Is there a subtle reason why this would be hard/impossible to implement? Something else entirely?
To test that second theory I wrote up a little code snippet that seems to work, but there may well be features of bind I haven't accounted for since it's just a fragment:
namespace b = boost;
template<class R, class B1, class A1>
b::_bi::bind_t<R, R (*) (B1), typename b::_bi::list_av_1<B1>::type>
mybind(R (*f) (B1), A1 a1)
{
typedef R (*F) (B1);
typedef typename b::_bi::list_av_1<B1>::type list_type;
return b::_bi::bind_t<R, F, list_type> (f, list_type(B1(a1)));
}
struct Convertible
{
Convertible(int a) : b(a) {}
int b;
};
int foo(Convertible bar)
{
return 2+bar.b;
}
void mainFunc()
{
int x = 3;
b::function<int()> funcObj = mybind(foo, x);
printf("val: %d\n", funcObj());
}
Because the functor may support multiple overloads, which may give different behaviours. Even if this signature could be resolved when you knew all the arguments (and I don't know if Standard C++ can guarantee this facility) bind does not know all the arguments, and therefore it definitely cannot be provided. Therefore, bind does not possess the necessary information.
Edit: Just to clarify, consider
struct x {
void operator()(int, std::vector<float>);
void operator()(float, std::string);
};
int main() {
auto b = std::bind(x(), 1); // convert or not?
}
Even if you were to reflect on the struct and gain the knowledge of it's overloads, it's still undecidable as to whether you need to convert the 1 to a float or not.
There are different cases where you need the arguments to be processed at the call site.
The first such example is calling a member function, where you can either have the member called on a copy of the object (boost::bind( &std::vector<int>::push_back, myvector)) which most probably you don't want, or else you need to pass a pointer and the binder will dereference the pointer as needed (boost::bind( &std::vector<int>::push_back, &myvector )) --Note both options can make sense in different programs
Another important use case is passing an argument by reference to a function. bind will copy performing the equivalent to a pass-by-value call. The library offers the option of wrapping arguments through the helper functions ref and cref, both of which store a pointer to the actual object to be passed, and at the place of call they dereference the pointer (through an implicit conversion). If the conversion to the target type was performed at bind time, then this would be impossible to implement.
I think this is due to the fact that bind has to work with any callable entity, be it a function pointer, std::function<>, or your own functor struct with operator(). This makes bind generic on any type that can be called using (). I.e. Bind's implicit requirement on your functor is just that it can be used with ()
If bind was to store the function argument types, it would have to somehow infer them for any callable entity passed in as a type parameter. This would obviously not be as generic, since deducing parameter types of an operator() of a passed-in struct type is impossible without relying on the user to specify some kind of typedef (as an example). As a result the requirement on the functor (or concept) is no longer concrete/simple.
I am not entirely sure this is the reason, but it's one of the things that would be a problem.
EDIT: Another point as DeadMG mentions in another answer, overloads would create ambiguities even for standard function pointers, since the compiler would not be able to resolve the functor type. By storing the types you provide to bind and using (), this problem is also avoided.
A good example would binding "std::future"s to some ordinary function taking ordinary types:
Say I want to use an ordinary f(x,y) function in an incredibly asynchronous way. Namely, I want to call it like "f(X.get(), Y.get())". There's a good reason for this- I can just call that line and f's logic will run as soon as both inputs are available (I don't need separate lines of code for the join). To do this I need the following:
1) I need to support implicit conversions "std::future<T> -> T". This means std::future or my custom equivalent needs a cast operator:
operator T() { return get(); }
2) Next, I need to bind my generic function to hide all its parameters
// Hide the parameters
template<typename OUTPUT, typename... INPUTS>
std::function<OUTPUT()> BindVariadic(std::function<OUTPUT(INPUTS...)> f,
INPUTS&&... in)
{
std::function<OUTPUT()> stub = std::bind( f, std::forward<INPUTS>(in)...);
return stub;
}
With a std::bind that does the "std::function<T> -> T" conversion at call time, I only wait for all the input parameters to become available when I ACTUALLY CALL "stub()". If it did the conversion via operator T() at the bind, the logic would silently force the wait when I actually constructed "stub" instead of when I use it. That might be fatal if "stub()" cannot always run safely in the same thread I built it.
There are other use cases that also forced that design choice. This elaborate one for async processing is simply the one I'm personally familiar with.
I'm trying to write predicate function for use with STL algorithms. I see that they are two ways to define a predicate:
(1) Use a simple function as below:
bool isEven(unsigned int i) { return (i % 2 == 0); }
std::find_if(itBegin, itEnd, isEven);
(2) Use the operator() function as below:
class checker {
public:
bool operator()(unsigned int i) { return (i % 2 == 0); }
};
std::find_if(itBegin, itEnd, checker);
I have more use for the second type as I usually would like to create a predicate object with some members in it and use them in the algorithm. When I add the same isEven function inside checker and use it as a predicate, I get an error:
3. Syntax which gives error:
class checker {
public:
bool isEven(unsigned int i)
{ return (i%2 == 0); }
};
checker c;
std::find_if(itBegin, itEnd, c.isEven);
Calling c.isEven gives an error during compilation saying undefined reference to some function. Can someone explain why 3. is giving error? Also, I would appreciate any pointers to read about predicate and iterator basics.
A pointer to a member function requires an instance to be called on, and you are passing only the member function pointer to std::find_if (actually your syntax is incorrect, so it doesn't work at all; the correct syntax is std::find_if(itBegin, itEnd, &checker::isEven) which then still doesn't work for the reasons I gave).
The find_if function expects to be able to call the function using a single parameter (the object to test), but it actually needs two to call a member function: the instance this pointer and the object to compare.
Overloading operator() allows you to pass both the instance and the function object at the same time, because they're now the same thing. With a member function pointer you must pass two pieces of information to a function that expects only one.
There is a way to do this using std::bind (which requires the <functional> header):
checker c;
std::find_if(itBegin, itEnd, std::bind(&checker::isEven, &c, std::placeholders::_1));
If your compiler doesn't support std::bind, you can also use boost::bind for this. Though there's no real advantage to doing this over just overloading operator().
To elaborate a bit more, std::find_if expects a function pointer matching the signature bool (*pred)(unsigned int) or something that behaves that way. It doesn't actually need to be a function pointer, because the type of the predicate is bound by the template. Anything that behaves like a bool (*pred)(unsigned int) is acceptable, which is why functors work: they can be called with a single parameter and return a bool.
As others have pointed out, the type of checker::isEven is bool (checker::*pred)(unsigned int) which doesn't behave like the original function pointer, because it needs an instance of checker to be called on.
A pointer to a member function can be conceptually considered as a regular function pointer that takes an additional argument, the this pointer (e.g. bool (*pred)(checker*, unsigned int)). You can actually generate a wrapper that can be called that way using std::mem_fn(&checker::isEven) (also from <functional>). That still doesn't help you, because now you have a function object that must be called with two parameters rather than only one, which std::find_if still doesn't like.
Using std::bind treats the pointer to a member function as if it was a function taking the this pointer as its first argument. The arguments passed to std::bind specify that the first argument should always be &c, and the second argument should bind to the first argument of the newly returned function object. This function object is a wrapper that can be called with one argument, and can therefore be used with std::find_if.
Although the return type of std::bind is unspecified, you can convert it to a std::function<bool(unsigned int)> (in this particular case) if you need to refer to the bound function object explicitly rather than passing it straight to another function like I did in my example.
I guess it's because the type of c.isEven() is,
bool (checker::*)(unsigned int) // member function of class
which may not be expected by find_if(). std::find_if should be expecting either a function pointer (bool (*)(unsigned int)) or a function object.
Edit: Another constraint: A non-static member function pointer must be called by the class object. In your case, even if you succeed to pass the member function then still find_if() will not have any information about any checker object; so it doesn't make sense to have find_if() overloaded for accepting a member function pointer argument.
Note: In general c.isEven is not the right way to pass member function pointer; it should be passed as, &checker::isEven.
checker::isEven is not a function; it is a member function. And you cannot call a non-static member function without a reference to a checker object. So you can't just use a member function in any old place that you could pass a function pointer. Member pointers have special syntax that requires more than just () to call.
That's why functors use operator(); this makes the object callable without having to use a member function pointer.
I prefer functors (function objects) because make your program more readable and, more importantly, expressing the intent clearly.
This is my favorite example:
template <typename N>
struct multiplies
{
N operator() (const N& x, const N& y) { return x * y; }
};
vector<int> nums{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Example accumulate with transparent operator functor
double result = accumulate(cbegin(nums), cend(nums), 1.1, multiplies<>());
Note: In recent years we've got a lambda expression support.
// Same example with lambda expression
double result = accumulate(cbegin(nums), cend(nums), 1.1,
[](double x, double y) { return x * y; });
The example given says you should use the call operator (operator()) whereas in your example you've called your function isEven. Try re-writing it as:
class checker {
public:
bool operator()(unsigned int i)
{ return (i%2 == 0); }
};
For example:
struct test
{};
void thing(test())
{}
int main()
{
thing(test());
}
This code would give me error; however, the next example won't give me error:
void thing(int())
{}
int main()
{
thing(int());
}
My main question is, why the first example isn't possible and the second one is? Ultimately, both test and int are types, so I can't think why declaring an anonymous object of test in the thing function argument list isn't possible whereas declaring an anonymous object of type int in the thing function argument list is.
It is possible; it's just that you're doing it wrong.
Here is a declaration of a function taking an unnamed parameter of type test:
void thing(test);
Here is a declaration of a function taking an unnamed parameter of type pointer-to-function-returning-test:
void thing(test());
You want the former, not the latter.
That your second code example works is actually a magical oddity, stemming from the fact that int() is 0 is a valid null pointer constant, which may be used to initialise a function pointer; the example breaks as soon as you swap int() for some other integer, or if you run the code in a completely compliant C++14 compiler (because C++14 made it so that 0 but not int() is a valid null pointer constant).