Why does this code compile? (tested with g++ and clang++)
The following code is for a factory method that accepts a function and creates a forwarding std::function out of it. As you can see, the lambda inside accepts const Arg&
arguments and forwards them to the given function.
In main()
I use factory()
to create a forwarder to test_func()
, which accepts a non-const reference parameter. What I don't understand is why this doesn't produce an error about discarding the const qualifier from the argument.
Note that indeed the instance of the class C
, created in main()
, is passed without creating any copies.
#include <functional>
#include <iostream>
class C
{
public:
C() {}
C(const C&)
{
std::cout << "C copy\n";
}
};
int test_func(C& cref)
{
return 0;
}
template<typename Ret, typename... Arg>
std::function<Ret (const Arg&...)> factory(Ret (*func) (Arg...))
{
return [ func ] (const Arg&... arg) -> Ret {
return (func)(arg...);
};
}
int main() {
auto caller = factory(test_func);
C c;
caller(c);
return 0;
}
As mentioned in the comments, you should use perfect forwarding (see Scott Meyers's presentation on Universal reference).
In your case, it should be :
#include <functional>
#include <iostream>
#include <utility>
class C
{
public:
C() {}
C(const C&)
{
std::cout << "C copy\n";
}
};
int test_func(const C& )
{
return 0;
}
template<typename Ret, typename... Arg>
std::function<Ret (Arg...)> factory(Ret (*func) (Arg...))
{
return [ func ] (Arg&&... arg) -> Ret {
return func(std::forward<Arg>(arg)...);
};
}
int main() {
auto caller = factory(test_func);
const C c;
caller(c);
}
Take a note that I changed C c;
to const C c;
in your main()
, and I modified the test_func.
If you want to avoid creating copies, you have to make sure the test_func function it not taking by value. It should take by reference (const of non-const).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With