Here is my code:
bool isNotValid (char a) {
if (isalpha(a) || a == '_')
{
cout << "\n- isalpha";
return 0;
}
else
{
cout << "\n- notalpha";
return 1;
}
}
bool test123(const string& test)
{
return find_if(test.begin(), test.end(), isNotValid) != test.end();
}
int main()
{
string test;
cout << "Test input: ";
cin >> test;
if (!test123(test))
cout << "\n- Valid\n";
else
cout << "\n- Not Valid\n";
return 0;
}
This is part of my code to check the validity of username in my program. I don't really understand what exactly I am iterating through when I insert the string into my function as address of the string. CPP reference states that find_if iterates from first to last position of a sequence.
Poked through the code with cout at different location, still didn't quite catch what is going on.
You are iterating your string. You did not pass the address of the string. The function takes the string as a reference to const, meaning it passes the actual string (no copy is made) and the function is not allowed to modify the string. You are iterating character by character in your string and calling your function isNotValid() on each character.
Notes:
Instead of returning 1 or 0 from isNotValid(), return true or false.
Consider flipping your logic and renaming the function to isValid() instead. You would also have to change test123() to use std::find_if_not(). Finally, you would check if the returned iterator is end() and not if it's not.
But, if you do change isNotValid() to isValid(), you'd be better off switching from std::find_if() entirely to to std::all_of(). It makes more sense, is more readable, and returns a bool directly (No need to compare against end()).
But if you want to keep your function isNotValid(), the comment that suggests using std::any_of() is what I would recommend for the same reasons.
Here's my take on your code:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool isValid(char a) {
return std::isalpha(static_cast<unsigned char>(a)) || a == '_'; // !
}
bool test123(const std::string& test) {
return std::all_of(test.begin(), test.end(), isValid); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
Output:
❯ ./a.out
Testing: i_am_valid : true
Testing: i_am_invalid_123 : false
I would argue that readability has stayed largely the same, but the mental load has been shifted; the Boolean flips make a bit more sense.
As you progress in your learning, you might not even want to have the function isValid() if it's a one-off thing. C++11 introduced lambdas, or functions as objects. C++20 also introduced ranges, so you don't have to pass a pair of iterators if you intend to iterate the whole container anyway.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
bool test123(const std::string& test) {
return std::ranges::all_of(test, [](const auto& c) {
return std::isalpha(static_cast<unsigned char>(c)) || c == '_';
}); // !
}
int main() {
std::string testOne{"i_am_valid"};
std::string testTwo{"i_am_invalid_123"};
std::cout << "Testing: " << testOne << " : " << std::boolalpha
<< test123(testOne) << '\n';
std::cout << "Testing: " << testTwo << " : " << std::boolalpha
<< test123(testTwo) << '\n';
}
That's a bit hairy to read if you're not familiar with lambdas, but I find lambdas useful for checks like this where you're just doing it the one time.
Related
I was experimenting with C++17 feature std::optional
The optional return type is std::optional<std::pair<int, int>>. I call the
sum_pair function in print_answer function and wanted a optional print.
In print_answer function I wanted to check whether the required pair holds something to show.
like in the example given in: optional-returning factory functions are usable as conditions of while and if
Following is the code: here is it live with error
#include <iostream>
#include <vector>
#include <unordered_map>
#include <optional>
typedef std::optional<std::pair<int, int>> returnType;
// following algorithum works fine: just to show,
// how I have used the std::optional
returnType sum_pair(const std::vector<int>& vec, const int sum)
{
std::unordered_map<int, int> compIndexMap;
int index = 0;
for(const int& ele: vec)
{
if(auto check = compIndexMap.find(sum - ele); check != compIndexMap.cend())
return returnType{std::make_pair(check->second, index)};
compIndexMap.emplace(sum - ele, index);
++index;
}
return std::nullopt;
}
// problem is here:
void print_answer(const std::vector<int>& vec, const int sum)
{
// if I uncomment the if-else, everything works
/*if*/(auto Pair = sum_pair(vec, sum) )?
std::cout << "Resulting indexes are: " << Pair->first << " " << Pair->second << std::endl: //;
//else
std::cout << "Nothing found!\n";
}
int main()
{
std::vector<int> vec0{ 1,3,2,8 };
const int sum = 8;
print_answer(vec0, sum);
return 0;
}
When I use the if-else statement in the following format
(condion) ? print something: print something else;
I get the following two errors. (used GCC 7.1)
||=== Build: Debug in MyTestProgram (compiler: GNU GCC Compiler) ===|
|25|error: expected primary-expression before 'auto'|
|25|error: expected ')' before 'auto'|
Can somebody explain, why I need to use if-else, but not with "operator ?" ?
if(auto Pair = sum_pair(vec, sum) )
std::cout << "Resulting indexes are: " << Pair->first << " " << Pair->second << std::endl;
else
std::cout << "Nothing found!\n";
this is valid C++. You are allowed to put a declaration in the opening condition of an if clause.
(auto Pair = sum_pair(vec, sum) )?
std::cout << "Resulting indexes are: " << Pair->first << " " << Pair->second << std::endl
:
std::cout << "Nothing found!\n";
this is not valid C++. Declarations are not expressions. There are places where expressions are allowed, but declararions are not. The left hand side of ?, the trinary operator, is one of them.
I found this code on cppreference.com. I was wondering if boost provides a similar function for its variant type. I found the boost documentation really awful and can't find anything.
int main()
{
std::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< std::holds_alternative<int>(v) << '\n'
<< "variant holds string? "
<< std::holds_alternative<std::string>(v) << '\n';
}
Although not exactly the same, you can use the pointer based get function:
boost::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< (boost::get<int>(&v) != nullptr) << '\n'
<< "variant holds string? "
<< (boost::get<std::string>(&v) != nullptr) << '\n';
You can create a simple wrapper that will work just like the standard one. Use the fact that boost::get has multiple overloads and when passed a pointer, it will also return a (possibly null) pointer.
template <typename T, typename... Ts>
bool holds_alternative(const boost::variant<Ts...>& v) noexcept
{
return boost::get<T>(&v) != nullptr;
}
It will be also picked up by ADL, so it doesn't matter much where you put it.
No but, you can use the type() method:
#include <iostream>
#include <boost/variant.hpp>
int main()
{
boost::variant<int, std::string> v = "abc";
std::cout << std::boolalpha
<< "variant holds int? "
<< (v.type() == typeid(int)) << '\n'
<< "variant holds string? "
<< (v.type() == typeid(std::string)) << '\n';
}
But it will not protect you against having the same type twice (boost::variant<int, int, std::string>) as std::holds_alternative would do.
I'm new to C++ and I have a vector of doctors.
I add a new doctor with the following code:
void DoctorAdmin::setDoctor(std::string lastname, std::string forename,
Person::Sex sex){
//Create new doctor
Doctor* doc = new Doctor(lastname, forename, sex);
//insert at the end of the vector
doctors.push_back(doc);
}
Then I want to show their information on the console:
void DoctorAdmin::showDoctors(){
cout << "Doctors:" << endl;
cout << "Name" << "\t\t\t" << "Forename" << "\t\t\t" << "Sex" << endl;
for (vector<Doctor*>::iterator i = doctors.begin(); i != doctors.end(); i++){
Doctors* doc = doctors.at(i);
cout << doc->getName() << "\t\t\t" << doc->getForename() << "\t\t\t"
<< doc->getSex() << endl;
}
After doing it like this I get two Errors:
E0304 No instance of overloaded function "std::vector<_Ty, _Alloc>::at [mit _Ty=Doctors *, _Alloc=std::allocator<Doctors *>]" matches the argument list.
// and
C2664 "Doctors *const &std::vector<Doctors *,std::allocator<_Ty>>::at(const unsigned int) const" : cannot convert from Argument "std::_Vector_iterator<std::_Vector_val<std::_Simple_types<_Ty>>>" in "const unsigned int"
How do I use the vector iterator correctly to avoid this?
An iterator is not index-like, it is pointer-like.
for (vector<Arzt*>::iterator doc = aerzte.begin(); doc != aerzte.end(); doc++)
{
cout << (*doc)->getName() << "\t\t\t" << (*doc)->getVorname() << "\t\t\t"
<< (*doc)->getGeschlecht() << endl;
}
It seems like you are confused as to when you need to new things too. Most of the time you don't need new
vector<Arzt> aerzte;
void ArztAdmin::anlegenArzt(std::string name, std::string vorname, Person::Geschlecht geschlecht){
// Create new doctor at the end of the vector
aerzte.emplace_back(name, vorname, geschlecht);
}
You can also directly bind references as loop variables
for (Arzt & doc : aerzte)
{
cout << doc.getName() << "\t\t\t" << doc.getVorname() << "\t\t\t"
<< doc.getGeschlecht() << endl;
}
The at function requires an index, but a vector<Arzt*>::iterator is not an index, neither semantically nor technically. An iterator points directly to an element, whereas an index represents the distance between a container's start and the element in a container that allows random element access.
Because an iterator points directly to an element, the at function isn't even necessary in your loop. *i yields the element:
Arzt* doc = *i;
Beginning with C++11, the code for such simple loops can be written in a shorter way using auto:
for (auto i = aerzte.begin(); i != aerzte.end(); i++){
The compiler knows what type i really is because it knows what begin() returns.
Even better, use a range-based loop:
for (auto doc : aerzte){
cout << doc->getName() << "\t\t\t" << doc->getVorname() << "\t\t\t"
<< doc->getGeschlecht() << endl;
}
And while we're at it, don't use dynamic memory allocation when you don't have to. This isn't Java or C#; new is dangerous territory in C++ and should be avoided:
#include <vector>
#include <string>
#include <iostream>
struct Arzt
{
Arzt(std::string const& name, std::string const& vorname) :
name(name),
vorname(vorname)
{
}
std::string name;
std::string vorname;
// Geschlecht omitted for brevity's sake
};
int main()
{
std::vector<Arzt> aerzte;
Arzt doc1("foo", "bar");
Arzt doc2("foo", "bar");
Arzt doc3("foo", "bar");
aerzte.push_back(doc1);
aerzte.push_back(doc2);
aerzte.push_back(doc3);
for (auto const& arzt : aerzte)
{
std::cout << arzt.name << ' ' << arzt.vorname << '\n';
}
}
As you are no longer iterating over pointers but over larger objects, const& should be used in the for loop.
My question is that of safety. I've searched cplusplus.com and cppreference.com and they seem to be lacking on iterator safety during std::move. Specifically: is it safe to call std::unordered_map::erase(iterator) with an iterator whose object has been moved? Sample code:
#include <unordered_map>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
class A {
public:
A() : name("default ctored"), value(-1) {}
A(const std::string& name, int value) : name(name), value(value) { }
std::string name;
int value;
};
typedef std::shared_ptr<const A> ConstAPtr;
int main(int argc, char **argv) {
// containers keyed by shared_ptr are keyed by the raw pointer address
std::unordered_map<ConstAPtr, int> valued_objects;
for ( int i = 0; i < 10; ++i ) {
// creates 5 objects named "name 0", and 5 named "name 1"
std::string name("name ");
name += std::to_string(i % 2);
valued_objects[std::make_shared<A>(std::move(name), i)] = i * 5;
}
// Later somewhere else we need to transform the map to be keyed differently
// while retaining the values for each object
typedef std::pair<ConstAPtr, int> ObjValue;
std::unordered_map<std::string, std::vector<ObjValue> > named_objects;
std::cout << "moving..." << std::endl;
// No increment since we're using .erase() and don't want to skip objects.
for ( auto it = valued_objects.begin(); it != valued_objects.end(); ) {
std::cout << it->first->name << "\t" << it->first.value << "\t" << it->second << std::endl;
// Get named_vec.
std::vector<ObjValue>& v = named_objects[it->first->name];
// move object :: IS THIS SAFE??
v.push_back(std::move(*it));
// And then... is this also safe???
it = valued_objects.erase(it);
}
std::cout << "checking... " << named_objects.size() << std::endl;
for ( auto it = named_objects.begin(); it != named_objects.end(); ++it ) {
std::cout << it->first << " (" << it->second.size() << ")" << std::endl;
for ( auto pair : it->second ) {
std::cout << "\t" << pair.first->name << "\t" << pair.first->value << "\t" << pair.second << std::endl;
}
}
std::cout << "double check... " << valued_objects.size() << std::endl;
for ( auto it : valued_objects ) {
std::cout << it.first->name << " (" << it.second << ")" << std::endl;
}
return 0;
}
The reason I ask is that it strikes me that moving the pair from the unordered_map's iterator may (?) therefore *re*move the iterator's stored key value and therefore invalidate its hash; therefore any operations on it afterward could result in undefined behavior. Unless that's not so?
I do think it's worth noting that the above appears to successfully work as intended in GCC 4.8.2 so I'm looking to see if I missed documentation supporting or explicitly not supporting the behavior.
// move object :: IS THIS SAFE??
v.push_back(std::move(*it));
Yes, it is safe, because this doesn't actually modify the key. It cannot, because the key is const. The type of *it is std::pair<const ConstAPtr, int>. When it is moved, the first member (the const ConstAPtr) is not actually moved. It is converted to an r-value by std::move, and becomes const ConstAPtr&&. But that doesn't match the move constructor, which expects a non-const ConstAPtr&&. So the copy constructor is called instead.
I have a list of functions that return bools. I want to iterate through the list of functions and write a message for each one "Test 1 passed", "Test 2 failed" etc.
My current solution is to create a vector of function pointers, push back each function and then loop through the vector. Code below. Is there a way to avoid the container without repeating the generic message (pass/fail) code for each test (imagine there would be hundreds of tests). It feels as if the vector is unnecessary or that there must be a more elegant solution for this.
typedef bool (*Tests)();
std::vector<Tests> tests;
tests.push_back(FASTA_FILE_READER_TEST);
tests.push_back(EXACT_MATCH_TEST);
for (int i = 0; i < tests.size(); i++) {
std::cout << "Test " << i + 1
<< (tests[i]() ? " PASSED" : " FAILED")
<< std::endl;
}
Is there anything stopping you using an array?
#include <iostream>
bool FASTA_FILE_READER_TEST() { return false; }
bool EXACT_MATCH_TEST() { return false; }
int main()
{
typedef bool (*Tests)();
Tests tests[] = {FASTA_FILE_READER_TEST, EXACT_MATCH_TEST};
for (int i = 0; i < sizeof(tests)/sizeof(Tests); i++) {
std::cout << "Test " << i + 1
<< (tests[i]() ? " PASSED" : " FAILED")
<< std::endl;
}
}
You could use a function to do that:
template<typename Functor>
void test(Functor& functor){
static int i = 0;
bool ret = functor();
if(ret){
std::cout << "Test " << i++ << " passed" << std::endl;
} else {
std::cout << "Test " << i++ << " failed" << std::endl;
}
}
void main(){
test(FASTA_FILE_READER_TEST);
test(EXACT_MATCH_TEST);
}
If you can use C++11 features:
#include <array>
#include <iterator>
#include <algorithm>
#include <iostream>
typedef bool (*Test)();
std::array<Test, 2> tests {{ FASTA_FILE_READER_TEST, EXACT_MATCH_TEST }};
void TestAll()
{
size_t i = 1;
std::for_each(std::begin(tests), std::end(tests),
[&i](Test& t)
{
std::cout << "Test " << i++ << (t() ? " PASSED" : " FAILED") << std::endl;
});
}
Demo.
It's another way of doing what you've already got (and your way is just fine, IMO). If the extra capacity a vector might have set aside bothers you, you can call shrink_to_fit() on it when you're done pushing back.
Create a class for each test. Then one static instance of each class.
Contructors of classes runs tests.
This of course may cause problems, because tests are executed before main() function is called.