std::find_if and lambda referencing structure field - c++11

In this question we have:
#include <list>
#include <algorithm>
struct S
{
int S1;
int S2;
};
int main()
{
std::list<S> l;
S s1;
s1.S1 = 0;
s1.S2 = 0;
S s2;
s2.S1 = 1;
s2.S2 = 1;
l.push_back(s2);
l.push_back(s1);
auto it = std::find_if(l.begin(), l.end(), [] (S s)
{ return s.S1 == 0; } );
}
But, if I want to find a match for s1.S1, I might try:
auto it = std::find_if(l.begin(), l.end(), [s1.S1] (S s)
{ return s.S1 == s1.S1; } );
I get a compiler error, however. This works:
auto foo = s1.S1;
auto it = std::find_if(l.begin(), l.end(), [foo] (S s)
{ return s.S1 == foo; } );
I think I understand why I need to introduce a temporary simple type as we can think of the [foo] as like a function parameter, but the use case of looking up a structure member would seem to be a frequent requirement, so what is the rationale for not supporting the usage? Or is there another way to avoid the temporary variable?

In C++11 I think you're stuck with adding in the intermediate variable. In C++14 you can use a capture with an initializer:
std::list<S>::iterator it = std::find_if(l.begin(), l.end(),
[foo = s1.S1] (S s) { return s.S1 == foo; } );
// ^^^^^^^^^^^^^

Related

When reassigning lambda, why called deleted copy assignment instead of move assignment?

I am implementing some sort of nested flat for_each (contrived example):
template <class InputIt, class UnaryFunction>
UnaryFunction flat_nested_for_each_of_sorts(InputIt first, InputIt last, UnaryFunction f) {
while (first != last) {
f = std::for_each(begin(*first), end(*first), std::move(f));
}
return f;
}
I want to return f, as it may be a struct with some data. But I want this function to work with lambdas as well. For example,
int example1() {
int acc = 0;
std::vector<std::vector<int>> values{{1,2},{3,4}};
auto l = [&acc](int i) {acc += i;};
l = flat_nested_for_each_of_sorts(begin(values), end(values), std::move(l));
return acc;
}
Problem is, compiler don't like this code:
error: use of deleted function 'example1()::<lambda(int)>& example1()::<lambda(int)>::operator=(const example1()::<lambda(int)>&)'
I know that in this case copy assignment operator of lambda with captures is deleted. What I don't understand is why not call move assignment operator? If we are to write lambda "by hand", everything works fine:
struct Lambda_sustitution {
int* acc;
Lambda_sustitution() = default;
Lambda_sustitution(int& acc) : acc{&acc} {}
Lambda_sustitution(const Lambda_sustitution&) = delete;
Lambda_sustitution& operator=(const Lambda_sustitution&) = delete;
Lambda_sustitution(Lambda_sustitution&& s) {
acc = s.acc;
s.acc = nullptr;
}
Lambda_sustitution& operator=(Lambda_sustitution&& s) {
acc = s.acc;
s.acc = nullptr;
return *this;
}
void operator()(int i) {*acc += i; };
};
int example2() {
int acc = 0;
std::vector<std::vector<int>> values{{1,2},{3,4}};
Lambda_sustitution l{acc};
l = flat_nested_for_each_of_sorts(begin(values), end(values), std::move(l));
return *l.acc;
}
Compiler Explorer link: https://godbolt.org/z/6Tb5WYqxj
What I don't understand is why not call move assignment operator?
Because lambda doesn't have a move assignment operator either (and it does have a copy constructor).
In fact, you don't need to do any reassignments, you can simply do:
template <class InputIt, class UnaryFunction>
UnaryFunction flat_nested_for_each_of_sorts(InputIt first, InputIt last, UnaryFunction f) {
while (first != last) {
std::for_each(begin(*first), end(*first), f);
++first;
}
return f;
}
And call it like:
int example1() {
int acc = 0;
std::vector<std::vector<int>> values{{1,2},{3,4}};
auto l = [&acc](int i) {acc += i;};
flat_nested_for_each_of_sorts(begin(values), end(values), l);
return acc;
}
Demo

Sort a vector of objects by a member of map in this vector

I have a very simple question i guess but...
I have to sort a vector by it's own member, but I can not.
This is my function for filling the vector with objects from another vector.
I have to sort the vector SortDealers by specific product but I don't know how to send the name of the Stock to my overloading operator<
void CShop::sortVector(const CStock& s1)
{
vector<CDealer> SortDealers;
vector<CDealer* >::iterator it = Dealers.begin();
while (it != Dealers.end())
{
if ((*(*it)).ComapareNameProducts(s1))
{
SortDealers.push_back(*(*it));
}
it++;
}
sort(SortDealers.begin(), SortDealers.end());
copy(SortDealers.begin(), SortDealers.end(), ostream_iterator<CDealer>(cout, "\n"));
}
this is overloading operator<:
I have to sort by unsigned member of the map.
bool CDealer::operator<(const CDealer & o1)
{
unsigned res1 = 0;
unsigned res2= 0;
map<const CStock, pair<unsigned, double>>::const_iterator it = Stock.begin();
map<const CStock, pair<unsigned, double>>::const_iterator iter = o1.Stock.begin();
while (it != Stock.end())
{
res1 += it->second.first;
it++;
}
while (iter != o1.Stock.end())
{
res2 += iter->second.first;
iter++;
}
return (res1 < res2);
}
You can use functor:
class less_than
{
const string stockname;
public:
less_than(string s) : stockname(s) {}
inline bool operator() const (const CDealer& a, const CDealer& b)
{
// use stockname here
}
};
sort(SortDealers.begin(), SortDealers.end(), less_than("name"));
Also you can use lambda expression providing stock name in its capture.
Related answer.

When move constructor will get called in C++11?

I am not able to understand why why move constructor is not getting called while move assignment is able to while if I use move function in Line X , it used to call the move constructor . Can anybody tell what will be the way or syntax to call the move constructor .
#include <iostream>
#include <cstring>
#include <algorithm>
#include <memory>
using namespace std;
class String
{
char *s;
int len;
public:
String():s(nullptr),len(0){ cout<<"Default "; }
String(char *p)
{
if(p)
{
len = strlen(p);
s = new char[len];
strcpy(s,p);
}
else
{
s = nullptr;
len = 0;
}
cout<<"Raw ";
}
String(String &p)
{
if(p.s)
{
len = strlen(p.s);
s = new char[len];
strcpy(s,p.s);
}
else
{
s = nullptr;
len = 0;
}
cout<<"Copy ";
}
String & operator = (const String & p)
{
if(this != &p)
{
delete []s;
s = nullptr;
len = 0;
if(p.len)
{
len = p.len;
s = new char[len];
strcpy(s,p.s);
}
}
cout<<"Assignment ";
return *this;
}
String( String && p):s(nullptr),len(0) // move constructor
{
len = p.len;
s = p.s;
p.s = nullptr;
p.len = 0;
cout<<"Move Copy ";
}
String & operator = (String && p) // move assignment
{
if(this != &p)
{
delete []s;
len = 0;
s = nullptr;
if(p.len)
{
len = p.len;
s = p.s;
p.s = nullptr;
p.len = 0;
}
}
cout<<"Move Assignment ";
return *this;
}
~String() { delete []s; cout<<"Destructor \n"; }
void show() { cout<<s<<endl; }
};
int main()
{
String s1("Something ");
String s2(s1);
s1.show();
s2.show();
String s4(String("Nothing ")); // Line X
s4.show();
String s5;
s5 = String(s2);
s5.show();
return 0;
}
OUTPUT:
Raw Copy Something
Something
Raw Nothing
Default Copy Move Assignment Destructor
Something
Destructor
Destructor
Destructor
Destructor
It's the second variant of the copy elision explained here: http://en.cppreference.com/w/cpp/language/copy_elision.
http://coliru.stacked-crooked.com/a/17f811a0be4ecba3
Note -fno-elide-constructors, it disables the optimization in g++.
Output:
Copy Something
Something
Raw Move Copy Move Copy Destructor
Destructor
Nothing
Default Copy Move Assignment Destructor
Something
Destructor
Destructor
Destructor
Destructor

How to return nullptr from a lambda function?

I have a small lambda function which shall find and return a QTreeWidgetItem. But if it does not find the given item, then it shall return a nullptr. But if I try to compile it then it gives me an error.
The function:
auto takeTopLevelItem = []( QTreeWidget* aTreeWidget, const QString& aText )
{
const int count = aTreeWidget->topLevelItemCount();
for ( int index = 0; index < count; ++index )
{
auto item = aTreeWidget->topLevelItem( index );
if ( item->text( 0 ) == aText )
{
return aTreeWidget->takeTopLevelItem( index );
}
}
return nullptr; // This causes a compilation error.
};
The error:
Error 1 error C3487: 'nullptr': all return expressions in a lambda must have the same type: previously it was 'QTreeWidgetItem *' cpp 251
I changed the mentioned line with this and now it compiles:
return (QTreeWidgetItem*)( nullptr );
but I would like to avoid this syntax. How can I solve this ?
I use Visual Studio 2012.
You can add an explicit return type annotation:
auto takeTopLevelItem = []( ... ) -> QTreeWidgetItem*
{
// ...
}
That way nullptr will be converted to your pointer type properly. You're getting that error because the lambda assumes no conversions should be made, and treats nullptr_t as a legitimate alternative return type.
As a side note, consider using (std::)optional instead. The nullability of pointers can be used to represent a missing return, but it doesn't mean it necessarily should be.
If you just want to avoid the syntax, rather than the casting, you could it like this:
static_cast<QTreeWidgetItem*>(nullptr);
I made a small example, on how Bartek's and mine's answer really work:
#include <iostream>
class A {
int a;
};
auto bla = [] (A* obj, bool flag) -> A* {
if(flag)
return obj;
return nullptr;
// return static_cast<A*>(nullptr);
};
int main() {
A obj;
A* ptr = &obj;
bool flag = false;
if( bla(ptr, flag) == nullptr)
std::cout << "ok\n";
return 0;
}
I had this very same issue with some Smart Pointers, so I found I could do this to avoid the issue:
auto myFunc= [](MyClass* class)
{
MyPointer* pointer = nullptr;
if( class && class->isValid() )
{
pointer = class->getPointerInstance()
}
return pointer;
}
Similarly, for shared pointer, just repleace MyPointer* by std::shared_ptr<MyPointer>.
So your code would looks like:
auto takeTopLevelItem = []( QTreeWidget* aTreeWidget, const QString& aText )
{
QTreeWidgetItem* item = nullptr;
const int count = aTreeWidget->topLevelItemCount();
for ( int index = 0; index < count; ++index )
{
auto item = aTreeWidget->topLevelItem( index );
if ( item->text( 0 ) == aText )
{
item = aTreeWidget->takeTopLevelItem( index );
break;
}
}
return item;
};

Simple Swift function return error

I am converting some algorithm pseudo code to Swift and have the following function:
func max(a: [Int], b: Int) {
var result = a[0]
var i: Int
for (i = 1; i <= b; i++) {
if (a[i] > result) {
result = a[i]
}
}
return result
}
I get an error when returning the result: 'Int' is not convertible to '()'
I've had a search online and can't find an answer to this question and am hoping someone can point me in the right direction.
Thanks
The return type is missing in the function declaration:
func max(inout a: [Int], b: Int) -> Int {
^^^^^^
Without a return type, swift defaults to an empty tuple (), and that's what the error means: int is not convertible to an empty tuple.
Also note that your return statement is misplaced: it should go right before the last closing bracket
}
return result
}
and not
return result
}
}
You must Implement the return type like this
func max(inout a: [Int], b: Int)-> Int {
var result = a[0]
var i: Int
for (i = 1; i <= b; i++) {
if (a[i] > result) {
result = a[i]
}
}
return result
}

Resources