std::forward Visual Studio 13 doesn't behave like I expect - c++

I'm trying to learn some basic C++ 11, using Scott Meyers lecture on youtube called "An Effective C++11/14 Sampler"
https://www.youtube.com/watch?v=BezbcQIuCsY
Using his sample code for std::forward (min 19 in the lecture) I wrote the following code to understand the effect of std::forward
#include "stdafx.h"
#include <string>
#include <utility>
class A
{
public:
void Foo(std::string&& s)
{
std::string s2 = std::forward<std::string>(s);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
std::string s3 = "Hello World";
a.Foo(s3);
a.Foo("Hello World");
return 0;
}
Surprisingly it doesn't compile, a.Foo(s3) can't implicitly cast from lvalue to rvalue. So I changed a.Foo(s3); to a.Foo(std::move(s3)); Now it compiles.
However on both calls to Foo std::forward<std::string>(s); resolved to an rvalue and a Move operation occurred (s was reset to "" as its buffer was pilfered).
So I really don't understand what good is std::forward and when it does apply. What am I missing here?

Calling std::forward<> when template argument deduction / reference collapsing isn't involved doesn't make sense.
The point of forwarding references (which Scott Meyers used to call "universal references") is that, depending on the value category of what you're receiving, you can forward that value category as well.
But here, you're not confused at all as to what's the value category, it's static.
Here is a context that has template argument deduction:
template<typename T>
void f(T&& t) // T is to be deduced, && might be collapsed
{
g(std::forward<T>(t)); // will keep the category value
}
f(std::string{"hey"}); // T inferred std::string&&, so the parameter type is `std::string&& &&`, which is collapsed to `std::string &&`.

You need a forwarding reference:
#include <string>
#include <utility>
class A
{
public:
template <typename String>
void Foo(String&& s)
{
std::string s2 = std::forward<String>(s);
}
};
int main()
{
A a;
std::string s3 = "Hello World";
a.Foo(s3);
a.Foo("Hello World");
return 0;
}
live example

Related

Is it possible to safely make a tuple of lvalue references for an aggregate object using fewer than three declarations?

I want to support some method, preferably named tie(), on my aggregate classes to allow callers to leverage various functionality involving std::tuple objects. The functionality is not limited to what is provided in the standard library.
My best attempt at a safe and fully featured implementation requires three overloads, as shown below.
#include <string>
#include <tuple>
#include <iostream>
struct Foo {
std::string s1;
std::string s2;
auto tie() const & { return std::tie(s1, s2); }
auto tie() & { return std::tie(s1, s2); }
// auto tie() && = delete;
};
int main()
{
auto refs = Foo{"this is a long string", ""}.tie();
std::cout << std::get<0>(refs); // <- prints garbage
return 0;
}
I rejected std::make_tuple due to performance concerns. Is there a better way to achieve the desired outcome?
The following technique achieves the desired outcome.
#include <string>
#include <tuple>
#include <iostream>
struct Foo {
std::string s1;
std::string s2;
friend auto tie(auto& foo) { return std::tie(foo.s1, foo.s2); }
};
int main()
{
auto foo = Foo{"", ""};
auto refs = tie(foo);
static_assert(std::tuple_size_v<decltype(refs)> == 2);
auto stdrefs = std::tie(foo);
static_assert(std::tuple_size_v<decltype(stdrefs)> == 1);
tie(Foo{"",""}); // cannot bind non-const lvalue reference error
return 0;
}

Should I precautionary move callables (e.g. lambdas?)

I have this striped-down example of a timer that I'd like to be instantiable with any kind of callable. Is it advisable to precautionary move the callable into a data member for efficiency?
#include <concepts>
#include <cstdio>
#include <string>
#include <utility>
template <std::invocable Cb>
class timer {
public:
timer(Cb cb)
: cb_ { std::move(cb) }
{
}
auto call()
{
cb_();
}
private:
Cb cb_;
};
int main()
{
std::string something_to_print = "Hello World!\n";
timer some_timer([&]() { printf(something_to_print.c_str()); });
some_timer.call();
return 0;
}
I can't see any difference in the assembly if I move or copy the lambda. Does it ever make a difference?
Your lambda has only reference captures. Moving an lvalue-reference does exactly the same as copying it. If you had [=] captures, the move would actually do something.
The answer to whether or not to do this in general is: "it depends on the situation." W.r.t. performance: measure.

error: passing 'const S' as 'this' argument discards qualifiers

Here is an simplified version of the problem from ported from large code base. I've solved the issue, but I don't like the way I solved it.
The problematic code that doesn't compile is this I'm starting with:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <array>
#include <utility>
#include <set>
#include <functional>
class S {
public:
int a;
int b;
mutable int c;
void set_c() { c = 222; }
};
struct cmp
{
bool operator()(const S& lhs, const S& rhs) const
{
return !(lhs.a == rhs.a && lhs.b == rhs.b);
}
};
class core {
public:
std::set<S, cmp> set_of_S;
std::function<void()> f;
void set_fn() {
f = [this]() {
auto it = set_of_S.begin();
it->set_c();
};
}
};
int main()
{
core core;
S a {.a = 2, .b = 3, .c = 0};
S b {.a = 2, .b = 3, .c = 0};
S c {.a = 2, .b = 4, .c = 0};
core.set_of_S.insert(a);
core.set_of_S.insert(b);
core.set_of_S.insert(c);
core.set_fn();
core.f();
std::cout << core.set_of_S.size() << '\n';
}
The compiler error is:
prog.cc: In lambda function:
prog.cc:37:23: error: passing 'const S' as 'this' argument discards qualifiers [-fpermissive]
it->set_c();
Ok, makes sense. As some people have told me, you should use the keyword mutable as this is not captured as a const and iterator it should be modifiable now (or atleast what I'm expecting):
void set_fn() {
f = [this]() mutable {
auto it = set_of_S.begin();
it->set_c();
};
}
This doesn't compile. This part doesn't make sense to me. So a member function cannot modify captured this inside lambda, but if you try to directly modify S::c inside the lambda compiler thinks that is okay. What? Doesn't make sense to me.
When I change:
void set_c() { c = 222; }
to
void set_c() const { c = 222; }
It will finally compile, but I don't like the solution, because we had to modify the original function signature just because the lambda won't accept it and it makes it less readable. I see lambdas as a tool and not something you have to design against. I have tried placing mutable keyword all over the place, but can't get it to compile. And I think there should be a way to permit member function to modify it's own state inside lambda.
Am I missing something or is this a compiler bug?
Here is the problematic code in wandbox: https://wandbox.org/permlink/qzFMW6WIRiKyY3Dj
I know this has been asked in: error: passing xxx as 'this' argument of xxx discards qualifiers but answers won't discuss on using mutable which to my understanding should solve these kind of situations.
Elements of a std::set<T> are unmodifiable - set_of_S.begin() returns a constant iterator: cppreference
Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions [begin/cbegin].
That means that the element pointed to by the iterator it is const, so you can't call a non-const function such as set_c on it. it->c = 300 still works because you've made c mutable. It has nothing to do with the lambda you're calling this in being mutable or not.

Using std::forward on sub fields

I was experimenting with how std::move and std::forward differs, and I have found that I am not able to use std::forward on class field:
name = std::forward<T>(rhs.name);
below is full example. The error I am getting under gcc 6.3 is:
C:/PROGRA~1/MINGW-~1/X86_64~3.0-P/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/move.h:89:7: error: static assertion failed: template argument substituting _Tp is an lvalue reference type
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
^~~~~~~~~~~~~
I understand that the cause is probably because T is of type WrongUseOfMove. But I wonder if forwarding only a sub variable is possible. For example I could use passed in rhs parameter and forward its fields to different class variables.
#include <iostream>
#include <string>
#include <vector>
class WrongUseOfMove {
public:
template<typename T>
WrongUseOfMove(T&& rhs)
{
//name = std::move(rhs.name); // Very wrong!!
//name = std::forward<T>(rhs.name); // Does not compile, T is WrongUseOfMove instead decltype(rhs.name);
name = std::forward<decltype(rhs.name)>(rhs.name); // compiles - but is it correct?
std::cout << __PRETTY_FUNCTION__ << "\n";
}
WrongUseOfMove(){}
std::string name;
};
int main()
{
WrongUseOfMove wm;
WrongUseOfMove wm2 = wm;
}
http://coliru.stacked-crooked.com/a/88d8591ee1478a3f
You may use the intuitive way:
name = std::forward<T>(rhs).name;
Demo
Your try:
name = std::forward<decltype(rhs.name)>(rhs.name);
does an unconditional move:
Demo

Using erase-remove idiom for function<void()>

Stacked people.
Iam trying to implement an observer(esque?) pattern for my program. I have a component which stores what functions should be called if an event occours. My prolem is that i dont know how should i erase my function from the container, if the need arises. Tried storing the functions by reference, but iam not sure how to do that(or if thats possible.)
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
class EventableComponent{
map<EVENT_TYPE, vector<function<void()>>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it();
}
}
void registerListener(EVENT_TYPE _et, function<void()> _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, function<void()> _fn){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove(listeners[_et].begin(), listeners[_et].end(), _fn), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
cin.get();
return 0;
};
Your problem can be reduced to the fact that two std::function instances cannot be compared for equality. std::remove requires operator==, and std::function does not have it. See "Why is std::function not equality comparable?".
Consider the following situation.
Let's say you defined two lambdas in your main:
auto fn = [](){cout << "Hello.\n"; };
auto fn2 = [](){cout << "Hello.\n"; };
Now, are those two equal or not? They do the same thing, but perhaps this is sheer coincidence. Would they become unequal if the second "Hello" became "Hello2"? Would they become unequal if the second one was no longer a lambda but a real function void f()?
The thing is that there can be no generally useful definition of equality for function objects, so it's up to you to define what equality really means in the context of your program.
You have several options to solve the problem at hand. One would be to operate on pointers to std::function objects. Pointers can be compared, and proper use of std::unique_ptr makes sure that deallocation is handled correctly.
Or you assign an identifier to every std::function you use. See the following modified example of your code in which direct storage of std::function<void()> in the vector is replaced with a custom type EventFunction that maps an int to the function object. The example uses std::remove_if to compare only the ints:
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
struct EventFunction {
function<void()> f;
int id;
};
class EventableComponent{
map<EVENT_TYPE, vector<EventFunction>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it.f();
}
}
void registerListener(EVENT_TYPE _et, EventFunction _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, int function_id){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove_if(listeners[_et].begin(), listeners[_et].end(),
[&](EventFunction const& e) { return e.id == function_id; }), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, EventFunction{ fn, 1 });
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, 1);
ec.trigger(EVENT_TYPE::anEvent);
};
Tried storing the functions by reference, but iam not sure how to do
that(or if thats possible.)
It's not possible because you cannot store references in standard-library containers. But I suppose the idea is similar to the one with pointers I mentioned above.