In the following code, it seems that the compiler sometimes prefer to call the templated constructor and fails to compile when a copy constructor should be just fine. The behavior seems to change depending on whether the value is captured as [v] or [v = v], I thought those should be exactly the same thing. What am I missing?
I'm using gcc 11.2.0 and compiling it with "g++ file.cpp -std=C++17"
#include <functional>
#include <iostream>
#include <string>
using namespace std;
template <class T>
struct record {
explicit record(const T& v) : value(v) {}
record(const record& other) = default;
record(record&& other) = default;
template <class U>
record(U&& v) : value(forward<U>(v)) {} // Removing out this constructor fixes print1
string value;
};
void call(const std::function<void()>& func) { func(); }
void print1(const record<string>& v) {
call([v]() { cout << v.value << endl; }); // This does not compile, why?
}
void print2(const record<string>& v) {
call([v = v]() { cout << v.value << endl; }); // this compiles fine
}
int main() {
record<string> v("yo");
print1(v);
return 0;
}
I don't disagree with 康桓瑋's answer, but I found it a little hard to follow, so let me explain it with a different example. Consider the following program:
#include <functional>
#include <iostream>
#include <typeinfo>
#include <type_traits>
struct tracer {
tracer() { std::cout << "default constructed\n"; }
tracer(const tracer &) { std::cout << "copy constructed\n"; }
tracer(tracer &&) { std::cout << "move constructed\n"; }
template<typename T> tracer(T &&t) {
if constexpr (std::is_same_v<T, const tracer>)
std::cout << "template constructed (const rvalue)\n";
else if constexpr (std::is_same_v<T, tracer&>)
std::cout << "template constructed (lvalue)\n";
else
std::cout << "template constructed (other ["
<< typeid(T).name() << "])\n";
}
};
int
main()
{
using fn_t = std::function<void()>;
const tracer t;
std::cout << "==== value capture ====\n";
fn_t([t]() {});
std::cout << "==== init capture ====\n";
fn_t([t = t]() {});
}
When run, this program outputs the following:
default constructed
==== value capture ====
copy constructed
template constructed (const rvalue)
==== init capture ====
copy constructed
move constructed
So what's going on here? First, note in both cases, the compiler must materialize a temporary lambda object to pass into the constructor for fn_t. Then, the constructor of fn_t must make a copy of the lambda object to hold on to it. (Since in general the std::function may outlive the lambda that was passed in to its constructor, it cannot retain the lambda by reference only.)
In the first case (value capture), the type of the captured t is exactly the type of t, namely const tracer. So you can think of the unnamed type of the lambda object as some kind of compiler-defined struct that contains a field of type const tracer. Let's give this structure a fake name of LAMBDA_T. So the argument to the constructor to fn_t is of type LAMBDA_T&&, and an expression that accesses the field inside is consequently of type const tracer&&, which matches the template constructor's forwarding reference better than the actual copy constructor. (In overload resolution rvalues prefer binding to rvalue references over binding to const lvalue references when both are available.)
In the second case (init capture), the type of the captured t = t is equivalent to the type of tnew in a declaration like auto tnew = t, namely tracer. So now the field in our internal LAMBDA_T structure is going to be of type tracer rather than const tracer, and when an argument of type LAMBDA_T&& to fn_t's constructor must be move-copied, the compiler will choose tracer's normal move constructor for moving that field.
For [v], the type of the lambda internal member variable v is const record, so when you
void call(const std::function<void()>&);
void print1(const record<string>& v) {
call([v] { });
}
Since [v] {} is a prvalue, when it initializes const std::function&, v will be copied with const record&&, and the template constructor will be chosen because it is not constrained.
In order to invoke v's copy constructor, you can do
void call(const std::function<void()>&);
void print1(const record<string>& v) {
auto l = [v] { };
call(l);
}
For [v=v], the type of the member variable v inside the lambda is record, so when the prvalue lambda initializes std::function, it will directly invoke the record's move constructor since record&& better matches.
Related
I can compile the following code without any problem (using gcc 11.1.0):
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f): f{_f} {};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
however I would like to perform some check in the constructor of the class K (for instance some std::is_convertible_v inside some bool function), so I tried to modify the code to
#include <iostream>
template <typename Func>
class K {
Func f;
public:
K(Func _f) {
...
f = _f;};
void do_thing(int x) {f(x);};
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl;};
K kl{f};
kl.do_thing(5);
return 0;
}
which however gives me some error message
error: use of deleted function ‘main()::<lambda(int)>::<lambda>()’
and then
note: a lambda closure type has a deleted default constructor
This confuses me a lot since I cannot understand how it is possible that the former piece of code could compile since the lambda function has not default constructor.
Question
How can I set my f inside the body of the constructor? (This is just a MWE and in my case the class is a bit more complex and the checks I mentioned before make sense.)
How can I initialize my f inside the body of the constructor?
You can't. f = _f; inside the constructor body is assignment but not initialization. So f will be default-initialized firstly, then enter the constructor body (to perform assignment).
You might use std::function instead; which could be default-initialized, then you can assign it in constructor body.
BTW: Since C++20 your code will compile fine even it might not work as you expected (depending on the ... part). For lambdas,
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).
Is this what you are looking for?
It is the generic solution, not making any assumptions on the signature of Fn
#include <iostream>
#include <utility>
template <typename Fn>
class K
{
public:
explicit K(const Fn& fn) :
m_fn{ fn }
{
};
template<typename... args_t>
auto do_thing(args_t&&... args)
{
return m_fn(std::forward<args_t>(args)...);
}
private:
Fn m_fn;
};
int main()
{
auto f = [](int x) {std::cout << x << std::endl; };
K kl{ f };
kl.do_thing(5);
}
In this example, a foo instance does nothing but print whether it's copy- or move-constructed.
#include <iostream>
#include <algorithm>
#include <vector>
struct foo {
foo()=default;
foo(foo &&) { std::cout << "move constructed\n"; }
foo(const foo &) { std::cout << "copy constructed\n"; }
};
int main()
{
foo x;
std::vector<int> v; // empty
std::remove_if(v.begin(), v.end(),
[x=std::move(x)](int i){ return false; });
}
This produces the following output:
move constructed
copy constructed
move constructed
move constructed
copy constructed
copy constructed
Questions:
Why does std::remove_if create so many closures ?
Even if multiple intermediate instances are necessary, one would expect they are all rvalues; so why are some of them copy-constructed ?
Compiler is gcc 8.1.1
If we take a look at the implementation of std::remove_if in gcc's libstdc++-v3 we notice that the predicate is passed down the call chain (by value, at times) a few steps before reaching the lowermost __find_if function (used by remove_if).
Let's count the moves and copies:
move constructed when the predicate (including the captured x) is sent by value, but as a non-lvalue, to std::remove_if entry point
copy constructed when passed on to the __gnu_cxx::__ops::__pred_iter(...) function, which in turn:
invokes the _GLIBCXX_MOVE macro, thus the move constructed,
which moves the predicate over to the _Iter_pred ctor which moves it (move constructed) into the _M_pred member.
The call from std::remove_if to std::__remove_if seems to be optimized, as the _Iter_pred is not an lvalue, I guess, but __remove_if in turn pass on the wrapped predicate, by value, to std::__find_if, for another copy constructed invocation.
std::__find_if, in turn, forwards the wrapped predicate, by value, to another __find_if overload, which is finally the sink of this call chain, and the final copy constructed.
It can be interesting to compare with e.g. clang's implementation of std::remove_if, as clang (6.0.1) do not produce this move-copy chain for OP's std::remove_if example. A quick glance shows that It seems as if clang use traits on the predicates type to make sure to pass the predicate as an lvalue reference.
Both clang and gcc produce the same move/copy chains for the contrived example that follows, which shows a similar chain to gcc's implementation:
#include <iostream>
#include <utility>
struct foo {
foo() = default;
foo(foo &&) { std::cout << "move constructed\n"; }
foo(const foo &) { std::cout << "copy constructed\n"; }
};
template <typename Pred>
struct IterPred {
Pred m_pred;
explicit IterPred(Pred pred) : m_pred(std::move(pred)) {}
};
template <typename T>
inline IterPred<T> wrap_in_iterpred (T l) {
return IterPred<T>(std::move(l));
}
template <typename T>
void find_if_overload(T l) {
(void)l;
}
template <typename T>
void find_if_entrypoint(T l) {
find_if_overload(l);
}
template <typename T>
void remove_if_entrypoint(T l) {
find_if_entrypoint(
wrap_in_iterpred(l));
}
int main()
{
foo x;
remove_if_entrypoint([x=std::move(x)](int){ return false; });
}
Where both gcc (8.2.0) and clang (6.0.1) produces the following chain:
move constructed
copy constructed
move constructed
move constructed
copy constructed
In code below, why F's move ctor is invoked?
I ran into this case when I tried to wrap std::function, and surprised to find that my inner functor was moved twice during construction.
#include <iostream>
using namespace std;
struct F {
F() { cout << "F()" << endl; }
F(const F &) { cout << "F(const F &)" << endl; }
F(F &&) {
cout << "F(F &&)" << endl;
}
void operator()() { cout << "F::()()" << endl;}
};
struct I {
#if 0
// F's move ctor not invoked
I(F &&) { }
#else
// F's move ctor invoked, why?
template<typename FT, typename = void>
I(FT) { } // Simulate std::function ctor prototype
#endif
};
struct FF {
FF(F &&f) : _impl(std::move(f)) {} // [line1] Debugger show source here
I _impl;
};
int main() {
FF ff = F();
(void)ff;
cout << "----" << endl;
return 0;
}
(using g++ 4.8.x-5.3.x)
gdb shows that the unexpected move ctor called by [line1], but I cannot comprehend it.
Could anyone explain it to me?
Besides, in my real case (replace class I by std::function), is there any way to construct wrapper class FF without the inner functor F moved twice?
Your templated version of the I constructor takes its parameter by value instead of by rvalue reference. The by-value parameter is constructed by the invocation of the move constructor that you're wondering about.
You need a 'universal reference' style constructor instead, which declares its parameter as an rvalue reference. This is the idiom that allows perfect forwarding as used by std::function and other constructs.
So change:
template<typename FT, typename = void>
I(FT) { } // Simulate std::function ctor prototype
To:
template<typename FT, typename = void>
I(FT&&) { } // Simulate std::function ctor prototype
To elaborate somewhat: you might have thought that by simply providing a value that has an rvalue reference type in your invocation, the compiler would instantiate the type FT to be an rvalue reference, i.e. F&&. However, that is not how template deduction works in this situation: the compiler will only deduce the 'decayed' type, i.e. F in this case. If you want the parameter to be a reference you must explicitly specify a reference type as your parameter.
I am trying to create a simple template enumerator class that should accept any object over which : operator is defined and later on print pairs of the form (i, v[i]). A simple implementation is the following:
template<typename T>
struct enumerator {
T &v; // reference to minimize copying
enumerator(T &_v) : v(_v) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
This works ok for things like:
Case A
vector<int> v({1,2,6,2,4});
auto e = enumerator(v);
e.do_enumerate();
However, I would also like it to handle temporary objects like:
Case B
auto e = enumerator(vector<int>({2,3,9});
e.do_enumerate();
This does not work and the compiler throws:
no matching function for call to ‘enumerator<std::vector<int> >::enumerator(std::vector<int>)
So, I tried to then add a
enumerator(T _t) : t(_T) {}
constructor to resolve this error. Now case A does not work and there is an error:
error: call of overloaded ‘enumerator(std::vector<int>&)’ is ambiguous
Moreover, in case B, the output of the enumeration is not correct.
What is the cleanest way to solve this? I would
really like both cases to be working
prefer not to use any libraries other than stdc++
want as little copying as possible (thus just storing a T t in the struct is not an option)
C++11 is not a problem. I have g++-4.8, which I presume has complete enough C++11 support.
Well I would like to copy in case the argument is an rvalue, and not copy in case it is not. Is that possible?
This can be accomplished using a make_enumerator helper function as shown.
template <class T>
struct enumerator {
T v;
enumerator(T&& _v) : v(std::forward<T>(_v)) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
template <class T>
enumerator<T> make_enumerator(T&& x) {
return enumerator<T>(std::forward<T>(x));
}
int main() {
vector<int> v {5, 2, 9, 1};
make_enumerator(v).do_enumerate();
make_enumerator(std::move(v)).do_enumerate();
}
How does this work?
If the argument to make_enumerator is an lvalue of type A then T is deduced as A& and we get the enumerator enumerator<A&>, whereas if it is an rvalue of type A then T is deduced as A and we get the enumerator enumerator<A>.
In the first case the member enumerator::v will have type A&, an lvalue reference that binds to the constructor argument (no copying). In the second case the member will have type A. The use of std::forward casts the parameter _v to an rvalue, so it will be moved from when it is used to initialize v.
This is a classic example where you don't actually need a class/struct (which actually introduce useless code) and you can just use good old functions:
template<typename Container>
void enumerate(const Container& t) {
std::size_t i = 0;
for(auto it = t.begin(); it != t.end(); ++it, ++i)
std::cout << i << *it << std::endl;
}
and then call it as:
enumerate(std::vector<int>{2,3,9});
Live demo
With this method you also get argument type inference for free (which you don't get with a struct).
I want to pass an rvalue through std::bind to a function that takes an rvalue reference in C++0x. I can't figure out how to do it. For example:
#include <utility>
#include <functional>
template<class Type>
void foo(Type &&value)
{
Type new_object = std::forward<Type>(value); // move-construct if possible
}
class Movable
{
public:
Movable(Movable &&) = default;
Movable &operator=(Movable &&) = default;
};
int main()
{
auto f = std::bind(foo<Movable>, Movable());
f(); // error, but want the same effect as foo(Movable())
}
The reason this fails is because when you specify foo<Movable>, the function you're binding to is:
void foo(Movable&&) // *must* be an rvalue
{
}
However, the value passed by std::bind will not be an rvalue, but an lvalue (stored as a member somewhere in the resulting bind functor). That, is the generated functor is akin to:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo<int>(arg0); // lvalue!
}
Movable arg0;
};
Constructed as your_bind(Movable()). So you can see this fails because Movable&& cannot bind to Movable.†
A simple solution might be this instead:
auto f = std::bind(foo<Movable&>, Movable());
Because now the function you're calling is:
void foo(Movable& /* conceptually, this was Movable& &&
and collapsed to Movable& */)
{
}
And the call works fine (and, of course, you could make that foo<const Movable&> if desired). But an interesting question is if we can get your original bind to work, and we can via:
auto f = std::bind(foo<Movable>,
std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
Movable()));
That is, we just std::move the argument before we make the call, so it can bind. But yikes, that's ugly. The cast is required because std::move is an overloaded function, so we have to specify which overload we want by casting to the desired type, eliminating the other options.
It actually wouldn't be so bad if std::move wasn't overloaded, as if we had something like:
Movable&& my_special_move(Movable& x)
{
return std::move(x);
}
auto f = std::bind(foo<Movable>, std::bind(my_special_move, Movable()));
Which is much simpler. But unless you have such a function laying around, I think it's clear you probably just want to specify a more explicit template argument.
† This is different than calling the function without an explicit template argument, because explicitly specifying it removes the possibility for it to be deduced. (T&&, where T is a template parameter, can be deduced to anything, if you let it be.)
You could use a lambda expression.
auto f = [](){ foo(Movable()); };
This would seem to be the simplest option.
Guys i have hacked up a perfect forwarding version of a binder(limited to 1 param) here
http://code-slim-jim.blogspot.jp/2012/11/stdbind-not-compatable-with-stdmove.html
For reference the code is
template <typename P>
class MovableBinder1
{
typedef void (*F)(P&&);
private:
F func_;
P p0_;
public:
MovableBinder1(F func, P&& p) :
func_(func),
p0_(std::forward<P>(p))
{
std::cout << "Moved" << p0_ << "\n";
}
MovableBinder1(F func, P& p) :
func_(func),
p0_(p)
{
std::cout << "Copied" << p0_ << "\n";
}
~MovableBinder1()
{
std::cout << "~MovableBinder1\n";
}
void operator()()
{
(*func_)(std::forward<P>(p0_));
}
};
As u can see from the above proof of concept, its very possible...
I see no reason why std::bind is incompatible with std::move... std::forward is after all for perfect forwarding I dont understand why there isnt a std::forwarding_bind ???
(This is actually a comment to GMan's answer, but I need some formatting for the code).
If generated functor actually is like this:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0;
};
then
int main()
{
auto f = your_bind(Movable());
f(); // No errors!
}
compliles without errors. as it's possible to assign and initialize data with rvalue and then pass a data value to rvalue argument of the foo(). However, I suppose that bind implementation extracts function argument type directly from foo() signature. i.e. the generated functor is:
struct your_bind
{
your_bind(Movable && arg0) :
arg0(arg0) // **** Error:cannot convert from Movable to Movable &&
{}
void operator()()
{
foo(arg0);
}
Movable&& arg0;
};
and indeed, this really fails to initialize rvalue data member.
Perhaps,the bind implpementation simply does not correctly extract "unreferenced" type from function argument type and uses this type for functor's data member declaration "as is", without trimming &&.
the correct functor should be:
struct your_bind
{
your_bind(Movable&& arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0; // trim && !!!
};
One more improvement in GManNickG's answer and I've got pretty solution:
auto f = std::bind(
foo<Movable>,
std::bind(std::move<Movable&>, Movable())
);
(works in gcc-4.9.2 and msvc2013)