C++ Copy_if using lambda - c++

I have an array of strings that I want to copy into a vector of strings only if a particular string's length is equal to a known value.
function(int len){
string lines[8]{
"a string",
"another string",
"and another"
etc..
}
vector<string> v (8);
std::copy_if(lines->begin(), lines->end(), std::back_inserter(v),
[len](std::string i) { return len == i.length(); });
The errors i get are:
error C2664: 'bool
Grid::SearchGrid::::operator
()(std::string) const': cannot convert argument 1 from 'char' to
'std::string'
error C2679: binary '=': no operator found which takes a right-hand
operand of type 'char' (or there is no acceptable conversion)
these are both happening within the algorithm header so I'm not sure where I'm going wrong. New to these new lambda expressions.

lines->begin() and lines->end() don't behavior as you expected. lines decays to string*, then lines->begin() will return the iterator on the 1st std::string of the array lines, and dereference on the iterator would get a char.
You could use std::begin and std::end instead.
std::copy_if(std::begin(lines), std::end(lines), std::back_inserter(v),
[len](std::string i) { return len == i.length(); });
BTW: vector<string> v (8); initializes v with 8 elements (empty std::strings); because you're using back_inserter later I think just vector<string> v; is enough. Otherwise you'll get 8+ elements in v at last.
Other issues: The function return type declaration seems lost; lambda parameter type could be changed to const std::string&.

Related

Conversion error when passing vector of type uint8_t to std::fill() in C++

I am using the below code snippet to pass vector of type "uint8_t" to std::fill()
size_t actual_size = 10;
std::vector<uint8_t> response;
std::fill(response.begin(), response.end() + actual_size, 0);
But i am getting the below warnings.
message : see reference to function template instantiation 'void std::fill<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>,int>(const _FwdIt,const _FwdIt,const int &)' being compiled
with
[
_Ty=uint8_t,
_FwdIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<uint8_t>>>
]
warning C4244: '=': conversion from 'const _Ty' to 'unsigned char', possible loss of data
with
[
_Ty=int
]
How to resolve this warning.
The reason you are getting the warning is because when filling 0(an int) to a vector<uint8_t>, you are implicitly converting an int to an uint8_t, which can potentially have data loss if the original int is not in the valid range of uint8_t.
To solve it, you can either create a uint8_t directly, or manually cast the int to uint8_t.
Also, when you do:
std::fill(vec.begin(), vec.end() + some_size, some_value)
You are literally filling elements pass the end iterator, without resizing the vector, which is likely not what you wanted.
Instead, you should use fill_n to specify the number of element to fill, and use back_inserter to push it to the vector:
std::fill_n(std::back_inserter(vec), some_size, some_value);
Or you can simply initialize the vector with the appropriate data filled:
std::vector<std::uint8_t> vec(some_size, some_value);
Or even zero initialize them, since you were going to assign them to 0s:
std::vector<std::uint8_t> vec(some_size);

Returning an array as a pointer

I'm trying to use a separate function to read a few data values in from a file; I'm getting two errors (I haven't used c++ in a long time...):
double * FREAD(std::string fpath){
std::string line;
double * params = new double[14];
std::ifstream parameters (fpath);
if (parameters.is_open())
{
for (int b = 0; b < 14; b++) {
parameters >> line >> params[b];
}
}
parameters.close();
return params;
}
throws
error C2556: 'double *FREAD(std::string)' : overloaded function differs only by return type from 'double FREAD(std::string)'
and
error C2040: 'FREAD' : 'double *(std::string)' differs in levels of indirection from 'double (std::string)'
The second issue is thrown from the line where I call the function in main.
double * param = FREAD(parampath);
error C2440: 'initializing' : cannot convert from 'double' to 'double *'
If I don't define param as a value pointed at by a double, I get the same type mismatch error in reverse...
My understanding is that I'm supposed to return a pointer which is directed at the first value of the array my subfunction has created and use that to work with the data. But I can't seem to pull this value when I call the function in main.
The simplest and fool-proof way to do it would be to return a container, for example
#include <array>
std::array<double,14> FREAD(const std::string& fpath)
{
std::string line;
std::array<double, 14> params;
// .... fill params
return params;
}
Concerning the overload error, you cannot overload a function by return type. It looks like the compiler is seeing these two declarations:
double * FREAD(std::string fpath);
double FREAD(std::string fpath);
Given the above suggestion, you should remove both of them anyway.
Your error C2556 is because you apparently have another FREAD() function that returns something else. The error is telling you that you can't overload functions based only on the return type.
Going from the messages, it appears to me that you have two functions:
double * FREAD(std::string fpath)
double FREAD(std::string fpath)
You only posted the first one.
C++ only allows you have two functions with the same name if they take different arguments (or const-ness for member functions). You should either give your functions different names, or pass in a token argument that the compiler can use to tell which one you want.

error C2664: cannot convert parameter 1 from 'const std::basic_string<_Elem,_Traits,_Ax>' to 'std::wstring &

error C2664: 'CCertStoreHelper::DeleteCtl' : cannot convert parameter 1 from 'const std::basic_string<_Elem,_Traits,_Ax>' to 'std::wstring &error C2664: 'CCertStoreHelper::DeleteCtl' : cannot convert parameter 1 from 'const std::basic_string<_Elem,_Traits,_Ax>' to 'std::wstring &
with
[
_Elem=wchar_t,
_Traits=std::char_traits<wchar_t>,
_Ax=std::allocator<wchar_t>
]
Conversion loses qualifiers
I have no idea regarding this. So kindly provide the solution.
Code:
CCertStoreHelper certCaStore;
std::set<std::wstring> ctlIdentifiersToRemove; // It populates data which I m not mentioning
std::set<std::wstring>::iterator iter1;
std::set<std::wstring>::iterator iter2;
for(iter1 = ctlIdentifiersToRemove.begin(); iter1 != ctlIdentifiersToRemove.end(); iter1++)
{
iter2 = ctlIdentifiersReferenced.find((*iter1));
if(iter2 == ctlIdentifiersReferenced.end())
{
if(certCaStore.DeleteCtl((*iter1))) // error line
{
// ...
}
}
}
// prototype for DeleteCtl fun is
bool CCertStoreHelper::DeleteCtl(std::wstring &ctlIdentifier)
Kindly correct me what i am doing wrong
Thanks
As twalberg points out, the most important bit of the compiler error message is the "loses qualifiers" bit. It also tells you that it can't convert from const std::wstring to std::wstring&, except that it expanded the first std::wstring into its full template instantiation form.
The issue is that your DeleteCtl takes the argument by non-const reference, as if it wants to modify the string there (bad idea), but it can't do that, because you're iterating over a set, and you cannot change the members of a set once they're in there (std::set doesn't make a difference between const_iterator and iterator, essentially). The reason is that std::set bases its internal structure on the values of its elements, and if you change those values, the internal structure becomes invalid, and horrible things happen.

why c++ accumulate third argument type cause compile failed

I write following codes in my editor,but it can't be compiled,it alerts:
cannot convert 'std::basic_string<char, std::char_traits<char>,
std::allocator<char> to 'const char*' in assignment|
||=== Build finished: 1 errors, 0 warnings ===|
Code:
#include <iostream>
//#inclide <algorithm>
#include <numeric>
#include <vector>
using namespace std;
int main()
{
std::vector<std::string> v;
v.push_back(string("a"));
v.push_back(string("b"));
v.push_back(string("c"));
string num = accumulate(v.begin(),v.end(),"");
std::cout << num;
return 0;
}
I don't know why it can't be compiled,please someone help me.Thanks:)
Paragraph 26.7.2/1 of the C++11 Standard specifies:
template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init);
[...]
1 Effects: Computes its result by initializing the accumulator acc with the initial value init and then
modifies it with acc = acc + *i [...] for every iterator i in the range
[first,last) in order.
[...]
String literals have type const char[], decaying to const char* when you pass them to functions. Therefore, the initializer you pass to accumulate() would be a const char*, and T would be a const char*.
This means acc from the expression above will be a const char*, and *i will be a string. Which means the following will not compile:
acc = acc + *i;
Because acc + *i yields a std::string, and on the left side of the assignment you have a const char*.
As other have suggested, you should do:
string num = accumulate(v.begin(),v.end(),string());
Also, you do not need to do:
v.push_back(string("a"));
When inserting strings into the vector. This is enough:
v.push_back("a");
An std::string will be implicitly constructed from the string literal "a".
One of the template parameters of std::accumulate is the return type, which would be deduced from the third function argument. This is also a type that should be capable of accumulating the values in the input iterator range. In your case, your return type should be std::string, but you are passing "", which is a const char[2]. This is not a type that can be copied and used for an accumulation.
You can fix this by passing an std::string:
string num = accumulate(v.begin(),v.end(), std::string());
Instead of "" as a third argument, explicitly call std::string():
string num = accumulate(v.begin(),v.end(),std::string());
The return type of std::accumulate is the same as the type of the third parameter, which is deduced to const char* in your case (because you're passing a string literal in).
This means that the function expects to work with const char*s internally, but the iterator range contains std::strings, so it barfs. That's why you must pass the correct type (std::string) in the third argument:
string num = accumulate(v.begin(), v.end(), std::string());

error C2664: in c++?

for (int v = 0; v <= WordChosen.length();v++)
{
if(Letter == WordChosen[v])
{
WordChosenDuplicate.replace(v,1,Letter);
}
}
I get this error
"Error 4 error C2664:
'std::basic_string<_Elem,_Traits,_Ax>
&std::basic_string<_Elem,_Traits,_Ax>::replace(__w64
unsigned int,__w64 unsigned int,const
std::basic_string<_Elem,_Traits,_Ax>
&)' : cannot convert parameter 3 from
'char' to 'const
std::basic_string<_Elem,_Traits,_Ax>
&' c:\documents and settings\main\my
documents\uni\2nd
year\tp2\hangman\hangman\hangman.cpp 147
"
I only got the error after putting this line in
WordChosenDuplicate.replace(v,1,Letter);
Or
WordChosenDuplicate.replace(v,1,std::string(Letter, 1));
The std::string::replace() function's parameters are incorrect or you need to invoke a different overload of replace. Something like:
WordChosenDuplicate.replace(v, // substring begining at index v
1, // of length 1
1, // replace by 1 copy of
Letter); // character Letter
What do you want to achieve? The version of replace that you are trying to call doesn't exist – as the compiler is telling you. Which of these versions do you mean?
It appears that WordChosenDuplicate is a std::string, in which case the 3rd parameter in the replace() method should be another std::string or a c-style const char*. You are trying to pass a single char instead ("Letter"). The error is saying that there is no version of replace() that takes a char as the 3rd parameter.