Strange behaviour of passing out refernce in binding of lambda function - c++11

I want to pass out some parameter from the lambda function, so I bind a reference parameter to a lambda function. However, the outer variable is not changed after calling the function. If I bind the lambda function with the pointer of outer variable, the result is correct.
I show the test program as follows and want to know why the outer variable does not change, given that I have already defined the pass-by-reference lambda function [&]?
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int main(int argc, char* argv[])
{
string acc_ref, acc_ptr;
// define function via reference
auto fProcRefEx = [&](string& acc, const string& s) -> void
{
acc += s;
};
auto fProcRef = bind(fProcRefEx, acc_ref, placeholders::_1);
// define function via pointer
auto fProcPtrEx = [&](string* pacc, const string& s) -> void
{
(*pacc) += s;
};
auto fProcPtr = bind(fProcPtrEx, &acc_ptr, placeholders::_1);
// test
vector<string> v = {"abc", "def"};
for_each(v.begin(), v.end(), fProcRef);
cout << "acc_ref: " << acc_ref << endl; // acc_ref is empty, wrong
for_each(v.begin(), v.end(), fProcPtr);
cout << "acc_ptr: " << acc_ptr << endl; // acc_ptr is "abcdef", correct
return 0;
}

I think std::bind will decay the reference to just a plain value type when it stores acc_ref. ie In the unspecified object instance returned from bind, it will have a member string acc_ref, not string& acc_ref. You have to use std::ref to make it really store a reference:
auto fProcRef = bind(fProcRefEx, ref(acc_ref), placeholders::_1);

Related

auto reference to address in C++

I'm studying some C++ features, trying to play around with some experiments. However, I stuck in a place where it compiled error:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "some string";
auto &c = str.begin(); // compile error
*c = toupper(*c);
cout << *c << ", str: " << str << endl;
}
I'm not sure why it was not acceptable. My thought was that c had type char * (a pointer to a char), so that's why I had written as above. But why it failed in compiling?
Error C2440 Cannot transform 'std::_String_iteratorstd::_String_val<std::_Simple_types<_Elem>>' to'std::_String_iterator<std::_String_val<std::_Simple_types<_Elem
PS: Another method which I had tried first was OK.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "some string";
auto &c = *str.begin(); // success
c = toupper(c);
cout << c << ", str: " << str << endl;
}
begin() returns an iterator by value, not a reference. You are not allowed to form a non-const lvalue reference.
Making it const would prolong the life of the returned iterator and the program would then compile:
const auto &c = str.begin();
On the other hand, iterators are supposed to be cheap to copy and iterators from contiguous containers are often implemented as pure pointers. The idiomatic approach is:
auto c = str.begin();
In your second example, the idiomatic approach to form a reference to the first element would be:
auto& c = str.front();

fail to capture random engine by value

I have this code that cannot be compiled by gcc 8, but I cannot understand why.
#include <iostream>
#include <algorithm>
#include <random>
using namespace std;
template<class... T>
void diagnose(T... x);
int main()
{
auto d = normal_distribution<double>(0.0, 1.0);
auto g = default_random_engine();
cout << d(g) << endl;
auto gen = [=](){
//diagnose(d, g);
return d(g); // ******
};
cout << gen() << endl;
}
The error message says (pointing to the line marked by *******):
error: no match for call to ‘(const std::normal_distribution<double>) (const std::linear_congruential_engine<long unsigned int, 16807, 0, 2147483647>&)
The code, however, works if I change the capture to be by reference.
If I uncomment the commented //diagnose line, the error message is like this (need also change return d(g) to return 1.0):
undefined reference to `void diagnose<std::normal_distribution<double>, std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul> >(std::normal_distribution<double>, std::linear_congruential_engine<unsigned long, 16807ul, 0ul, 2147483647ul>)'
As you can see, in the capture-by-value case, the parameter g is a const reference. But the const does not appear in diagnosis.
Can somebody explain what is going on here?
You are passing d by value [=] so copy of this object is created inside lambda, but body of lambda function is const so you cannot change object inside lambda body. normal_distribution::operator() member is not-const. In const members you can invoke only const methods for member objects. You can resolve it by adding mutable to lambda
auto gen = [=]() mutable {
//diagnose(d, g);
return d(g); // ******
};
or passing d by reference
auto gen = [&](){
//diagnose(d, g);
return d(g); // ******
};

C++ range-for and boost::irange

I'm using boost::irange and created a helper function to simplify the code by removing the need for explicit template parameters. I don't understand why it doesn't work. Here's the code:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
boost::irange<T> range_from_zero(T limit)
{
return boost::irange<T>(T(), limit);
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(0,end))
std::cout << i << ' ';
return 0;
}
There's a live version here https://ideone.com/VVvW6e, which produces compilation errors
prog.cpp:5:8: error: 'irange<T>' in namespace 'boost' does not name a type
boost::irange<T> range_from_zero(T limit)
^
prog.cpp: In function 'int main()':
prog.cpp:12:41: error: 'range_from_zero' was not declared in this scope
for (auto i : range_from_zero(0,end))
If I use boost::irange directly in the range-for, then it works:
#include <iostream>
#include <boost/range/irange.hpp>
int main() {
size_t end = 100;
for (auto i : boost::irange<size_t>(0,end))
std::cout << i << ' ';
return 0;
}
this works fine: https://ideone.com/TOWY6H
I thought maybe is was a problem using range-for on the return of a function, but it isn't; this works using a std::vector:
#include <iostream>
#include <boost/range/irange.hpp>
template<typename T>
std::vector<T> range_from_zero(T limit)
{
auto range = boost::irange<T>(T(), limit);
return { std::begin(range), std::end(range) };
}
int main() {
size_t end = 100;
for (auto i : range_from_zero(end))
std::cout << i << ' ';
return 0;
}
See https://ideone.com/TYRXnC
Any ideas, please?
But, first off, what's wrong with Live On Coliru
for (size_t i : irange(0, 100))
or even Live On Coliru
size_t end = 100;
for (auto i : irange(0ul, end))
irange is a function template, and it cannot be used as a return type.
The return type is integer_range or strided_integer_range. As such, irange is already the function you were looking for.
Only, you didn't pass arguments that could be unambiguously deduced. If you can to allow this, "copy" irange() implementation using separate template argument types for the boundary values and use e.g. std::common_type<T1,T2>::type as the range element.
Here's my stab at writing range_from_zero without naming implementation details in the interface:
Live On Coliru
#include <iostream>
#include <boost/range/irange.hpp>
template <typename T>
auto izrange(T upper) -> decltype(boost::irange(static_cast<T>(0), upper)) {
return boost::irange(static_cast<T>(0), upper);
}
int main() {
size_t end = 100;
for (size_t i : izrange(end))
std::cout << i << ' ';
}

Is this an example of reference reassignment? C++11

As I understand it, one cannot change the reference variable once it has been initialized. See, for instance, this question. However, here is a minmal working example which sort of does reassign it. What am I misunderstanding? Why does the example print both 42 and 43?
#include <iostream>
class T {
int x;
public:
T(int xx) : x(xx) {}
friend std::ostream &operator<<(std::ostream &dst, T &t) {
dst << t.x;
return dst;
}
};
int main() {
auto t = T(42);
auto q = T(43);
auto &ref = t;
std::cerr << ref << std::endl;
ref = q;
std::cerr << ref << std::endl;
return 0;
}
You're not changing the reference here.
You are replacing the object the reference is referring to.
In other words: after the assignment, your t is replaced by q.
ref is still a reference to t.
That does not perform a reference reassignment. Instead, it copy assigns the object in variable q into the object referenced by ref (which is t in your example).
This also justifies why you got 42 as output: the default copy assignment operator modified the first object.

How tu use a C++11 lambda asynchronously when capturing by reference

Can somebody explain the behavior of the following code?
When I explicitely convert my lambda to an std::function, the lambda correctly captures my variable n.
When it is implicitly converted to an std::function (using a temporary), then the capture fails.
I am using g++-4.9 (Ubuntu 4.9-20140406-1ubuntu1) 4.9.0 20140405 (experimental) [trunk revision 209157]
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
std::shared_ptr<std::thread> call(const std::function<void()>& functor)
{
// Execute our functor asynchronously
return std::make_shared<std::thread>([&functor]
{
// Make sure all temporary are deallocated
std::this_thread::sleep_for(std::chrono::seconds(1));
// Execute our functor
functor();
});
}
int main()
{
int n{};
std::cout << "in main " << &n << std::endl;
// -> in main 0x7fffd4e1a96c
auto lambda = [&n]
{
std::cout << "in lambda " << &n << std::endl;
};
// Here we do an explicit convertion to std::function
std::cout << "explicit convertion" << std::endl;
auto function = std::function<void()>{ lambda };
auto pThreadFunction = call(function);
pThreadFunction->join();
// -> in lambda 0x7fffd4e1a96c
// Here we use an implicit convertion to std::function
std::cout << "implicit convertion" << std::endl;
auto pThreadLambda = call(lambda);
pThreadLambda->join();
// -> in lambda 0
return 0;
}
The lifetime of a temporary constructed for binding to a const reference function parameter is the full-expression containing that function call, so your thread function is referring to a dangling reference.
You should only capture variables into a thread function by reference if you can guarantee that the lifetime of the variable contains the lifetime of the thread, as you have done in the case where function is a local variable in main.
One alternative would be to call join within the full-expression that constructs the temporary:
call(lambda)->join();
Another more general solution would be to capture functor by value in your thread function.

Resources