c++ find_if lambda - c++

What is wrong with the code below? It is supposed to find an element in the list of structs if the first of the struct's members equals to 0. The compiler complains about the lambda argument not being of type predicate.
#include <iostream>
#include <stdint.h>
#include <fstream>
#include <list>
#include <algorithm>
struct S
{
int S1;
int S2;
};
using namespace std;
int main()
{
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);
list<S>::iterator it = find_if(l.begin(), l.end(), [] (S s) { return s.S1 == 0; } );
}

Code works fine on VS2012, just one recommendation, pass object by reference instead of pass by value:
list<S>::iterator it = find_if(l.begin(), l.end(), [] (const S& s) { return s.S1 == 0; } );

Related

Passing variable length argument to function C++

I am trying to create a function that accepts variable number of arguments. But I am getting error in expression decltype(std::initializer_list::size_type) res1=0; as error: expected primary-expression before 'decltype'. The purpose is to declare appropriate variable type that can hold sum of the list (although this declaration will create big enough variable to hold all elements of the list only and not their sum). How can I do this?
Also, how can I make appropriate function return type to return res1 instead of void?
#include <iostream>
#include <initializer_list>
void sum1(std::initializer_list<int> lst1)
{
decltype(std::initializer_list::size_type) res1=0;
for(auto v1:lst1)
{
res1 += v1;
}
std::cout<<" sum = \n"<<res1;
}
int main()
{
sum1({1,2,3,4,5,6,7,8,9,10});
//auto b = sum1({1,2,3,4,5,6,7,8,9,10});
return 0;
}
size_type is not needed for anything in your function. The initializer_list has type int, therefore res1 should be an int and your return type should be int. If you really want to derive the value type from the initializer_list then do so like this:
#include <iostream>
#include <initializer_list>
auto sum1(std::initializer_list<int> lst1)
{
typename std::initializer_list<int>::value_type res1 = 0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
sum1({1,2,3,4,5,6,7,8,9,10});
auto b = sum1({1,2,3,4,5,6,7,8,9,10});
std::cout << b << std::endl;
return 0;
}
If you want the function to be generic, in which case it is necessary to derive the value type, then the template function looks like this.
#include <iostream>
#include <initializer_list>
template<typename T>
auto sum1(std::initializer_list<T> lst1)
{
typename std::initializer_list<T>::value_type res1 = 0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
sum1({1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10});
auto b = sum1({1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10});
std::cout << b << std::endl;
return 0;
}
Following is corrected code.
#include <iostream>
#include <initializer_list>
int sum1(std::initializer_list<int> lst1)
{
int res1=0;
for(auto v1:lst1)
{
res1 += v1;
}
return res1;
}
int main()
{
std::cout<<" sum = "<<sum1({1,2,3,4,5,6,7,8,9,10});
//auto b = sum1({1,2,3,4,5,6,7,8,9,10});
return 0;
}
You can see working here.
Note: You can change the type of res0 to long or other type if result is not in the limits of int. Also, Change the return type of function sum1 accordingly.

Custom Functor in std::set

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int order[26];
struct lexcmp
{
bool operator()(const string &s1,const string &s2)
{
int i=0;
int j=min(s1.size(),s2.size());
while(1)
{
if(order[s1[i]-'a']<order[s2[i]-'a'])
return true;
if(order[s1[i]-'a']>order[s2[i]-'a'])
return false;
if(i==j-1)
return false;
i++;
}
}
};
int main()
{
string s;
cin>>s;
for(int i=0;i<s.size();i++)
{
order[s[i]-'a']=i;
}
set<string,lexcmp> store;
int m;
cin>>m;
while(m--)
{
string q;
cin>>q;
store.insert(q);
}
for(auto i=store.begin();i!=store.end();i++)
{
cout<<*i<<endl;
}
}
return 0;
}
Problem in making the Custom Functor
The problem is, i have a new order of elements (instead of simple a-z). //Saved in order array
All i want is order the given strings on the based of new order.
for eg: Order is : bacdefghijklmnopqrstuvwxyz
So if the strings are ss , aa , bb
The new ordering will be bb,aa,ss.
The Code is working fine but it is giving me a problem while the strings are like "pas" "p" to be compared.
p should come before pas but it is coming after.
What modifications should i do in the functor?
Here's one approach:
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <algorithm>
#include <numeric>
#include <array>
#include <string>
#include <locale>
struct lexcmp {
lexcmp() { std::iota(order_.begin(), order_.end(), std::int_fast8_t{}); }
explicit lexcmp(std::string const& order) {
assert(order.size() == order_.size());
for (std::size_t i{}; i != order_.size(); ++i) {
char const order_letter = order[i];
assert(std::isalpha(order_letter, std::locale::classic()));
assert(std::islower(order_letter, std::locale::classic()));
order_[i] = order_letter - 'a';
}
auto unique_order_letters = [this]{
auto order = order_;
std::sort(order.begin(), order.end());
return order.end() - std::unique(order.begin(), order.end()) == 0;
};
assert(unique_order_letters());
}
bool operator ()(std::string const& a, std::string const& b) const {
auto const a_len = a.size(), b_len = b.size();
std::size_t i{};
for (auto const len = std::min(a_len, b_len); i != len; ++i) {
if (auto const diff = order_[a[i] - 'a'] - order_[b[i] - 'a']) {
return diff < 0;
}
}
return i == a_len && i != b_len;
}
private:
std::array<std::int_fast8_t, 26> order_;
};
Online Demo

unresolved identifier on .begin() and .end()?

i keep getting this error "unresolved identified" on l_vector.begin() and l_vector.end, specifically on the begin and end functions, why is it not recognizing these simple vector functions?
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <vector>
#include <string>
using namespace std;
// function prototype
int FindIndexOfLargest(vector<int> l_vector);
int main()
{
int FindIndexOfLargest();
return 0;
}
//function definition
int FindIndexOfLargest(vector<int> l_vector)
{
vector<int>:: const_iterator iter;
int current_max_location = 0;
int current_max = 0;
for(iter = l_vector.begin(); iter != l_vector.end(); ++iter)
{
if(*iter > current_max)
{
current_max_location = iter;
}
return current_max;
}
}
I see a few causes for compilation failure.
int FindIndexOfLargest();
You have to pass an std::vector <int> to this function when you call it in main().
And finally, your function int FindIndexOfLargest(vector<int> l_vector) must return an int value.
An alternate way to write this function is to use std::max_element and std::distance.
std::size_t FindIndexOfLargest(const std::vector <int> &input)
{
std::vector<int>::const_iterator max_value =
std::max_element(input.cbegin(), input.cend());
if (max_value != input.cend()) {
return std::distance (input.cbegin(), max_value);
}
// Otherwise, throw an expection or return an error value here.
}

How do I pass an index of a stl string to a function in c++?

I am currently stuck with a slight problem where I want to swap contents in a std::string.
#include <iostream>
#include <string>
void swap(char* t1, char* t2); // function parameter is wrong syntax
int main(){
std::string message = "ABC";
swap(message[0], message[1]); // parameter probably wrong here
return 0;
}
void swap(char * t1, char * t2){
return;
}
GOAL: I wish to do a simple swap of the contents in index 0 and 1 such that after swapping it, the message "ABC" becomes "BAC". As you can see, I tried doing it like I was using a normal array, but it seems this logic doesn't work with strings. I understand that if I switch to
char a[] = "ABC";
it would work, but I wanna try it using the string class.
The type of message[n] is char. So the signature of your swap function should be
swap(char& a, char& b);
But you should use std::swap instead.
#include <iostream>
#include <string>
#include <utility>
int main(){
std::string message = "ABC";
std::swap(message[0], message[1]);
std::cout << message << std::endl;
}
Try the following
#include <iostream>
#include <string>
void swap( char *c1, char *c2 )
{
char tmp = *c1;
*c1 = *c2;
*c2 = tmp;
}
void swap( char &c1, char &c2 )
{
char tmp = c1;
c1 = c2;
c2 = tmp;
}
int main()
{
std::string message = "ABC";
swap( message[0], message[1] );
swap( &message[1], &message[2] );
return 0;
}
If you want to use standard utilities then the program above can look the following way
#include <iostream>
#include <string>
#include <utility>
int main()
{
std::string message = "ABC";
std::swap( message[0], message[1] );
message[1] = std::exchange( message[2], message[1] );
return 0;
}

Cannot use .begin() or .end() on an array

The error reads:
request for member 'begin', 'end' in 'arr' which is non class type int[5],
unable to deduce from expression error.
My code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
int arr[5] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr.begin(); it != arr.end(); ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Arrays have no member functions as they aren't a class type. This is what the error is saying.
You can use std::begin(arr) and std::end(arr) from the <iterator> header instead. This also works with types that do have .begin() and .end() members, via overloading:
#include <array>
#include <vector>
#include <iterator>
int main()
{
int c_array[5] = {};
std::array<int, 5> cpp_array = {};
std::vector<int> cpp_dynarray(5);
auto c_array_begin = std::begin(c_array); // = c_array + 0
auto c_array_end = std::end(c_array); // = c_array + 5
auto cpp_array_begin = std::begin(cpp_array); // = cpp_array.begin()
auto cpp_array_end = std::end(cpp_array); // = cpp_array.end()
auto cpp_dynarray_begin = std::begin(cpp_dynarray); // = cpp_dynarray.begin()
auto cpp_dynarray_end = std::end(cpp_dynarray); // = cpp_dynarray.end()
}
For a standard fixed-length C array, you can just write
int c_array[] = {1,3,5,7,9}, acc = 0;
for (auto it : c_array) {
acc += it;
}
The compiler does the behind-the-scenes work, eliminating the need to create all those begin and end iterators.
In C++, arrays are not classes and therefore do not have any member methods. They do behave like pointers in some contexts. You can take advantage of this by modifying your code:
#include <iostream>
using namespace std;
int main()
{
int * mypointer;
const int SIZE = 5;
int arr[SIZE] = {1,3,5,7,9};
mypointer = arr;
for(auto it = arr; it != arr + SIZE; ++it) {
cout<<*mypointer<<endl;
mypointer++;
}
return 0;
}
Of course, this means that mypointer and it both contain the same address, so you don't need both of them.
One thing I'd like to point out for you is that you really don't have to maintain a separate int* to use in dereferencing the array elements, apart from the whole member thing others have well pointed out.
Using a more modern approach, the code is both more readable, as well as safer:
#include <iostream>
#include <algorithm>
#include <array>
#include <iterator>
using namespace std;
int main()
{
std::array<int, 5> cpp_array{1,3,5,7,9};
// Simple walk the container elements.
for( auto elem : cpp_array )
cout << elem << endl;
// Arbitrary element processing on the container.
std::for_each( begin(cpp_array), end(cpp_array), [](int& elem) {
elem *= 2; // double the element.
cout << elem << endl;
});
}
Using the lambda in the second example allows you to conveniently perform arbitrary processing on the elements, if needed. In this example, I'm just showing doubling each element, but you can do something more meaningful within the lambda body instead.
Hope this makes sense and helps.
Perhaps here is a cleaner way to do it using templates and lambdas in c++14:
Define:
template<typename Iterator, typename Funct>
void my_assign_to_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
*start = f();
++start;
}
}
template<typename Iterator, typename Funct>
void my_read_from_each(Iterator start, Iterator stop, Funct f) {
while (start != stop) {
f(*start);
++start;
}
}
And then in main:
int x[10];
srand(time(0));
my_assign_to_each(x, x+10, [] () -> int { int rn{}; rn = rand(); return rn; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
int common_value{18};
my_assign_to_each(x, x+10, [&common_value] () -> int { return common_value; });
my_read_from_each(x, x+10, [] (int value) { std::cout << value << std::endl; });
Quite late but I think it's worth to mention that:
void findavgTime(int n)
{
int wt1[n];
fill_wt(wt1,n); //Any method that puts the elements into wt1
int wt2[3];
int sum = accumulate(begin(wt1), end(wt1), 0); // Fails but wt2[3] will pass. Reason: variable-sized array type ‘int [n]’ is not a valid template argument)
}