declaration inside if condition [duplicate] - c++

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.

Related

What am I iterating in this find_if function?

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.

C++17 std::optional error: expected primary-expression before 'auto'

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.

Conceptual issue with range based iteration over multiple std containers using boost

I have a function which "zips" multiple containers for range based foor loop iteration. (taken from a another Stack Overflow post)
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype(boost::make_iterator_range(boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...)))) {
return {boost::make_zip_iterator(boost::make_tuple(conts.begin()...)),
boost::make_zip_iterator(boost::make_tuple(conts.end()...))};
}
I can use this function like so:
std::vector<int> x({1,2,3});
std::vector<int> y({4,5,6});
for ( auto const& entries : zip_range(x,y) ) {
std::cout << entries.get<0>() << " " << entries.get<1>() << std::endl;
}
And get expected behavior:
1 4
2 5
3 6
If I try to define a function which takes two std::initizalizer_list arguments, passes them to a vector, and tries to loop:
template <class T1, class T2>
void foo(const std::initializer_list<T1>& il1,
const std::initializer_list<T2>& il2) {
std::vector<T1> v1(il1);
std::vector<T2> v2(il2);
for ( auto const& zipitr : zip_range(v1,v2) ) {
std::cout << zipitr.get<0>() << " " << zipitr.get<1>() << std::endl;
}
}
I get a compilation error that isn't very helpful:
testing.cpp: In function ‘void foo(const std::initializer_list<_Tp>&, const std::initializer_list<T2>&)’:
testing.cpp:34:32: error: expected primary-expression before ‘)’ token
std::cout << zipitr.get<0>() << " " << zipitr.get<1>() << std::endl;
^
testing.cpp:34:58: error: expected primary-expression before ‘)’ token
std::cout << zipitr.get<0>() << " " << zipitr.get<1>() << std::endl;
Why am I unable to do this? (much less go straight to giving the initializer lists to the function zip_range)
The type of zipitr is dependent on T1 and T2 and that type has a nested member function template get. So to tell the compiler get is a dependent function template, you need to add the template keyword immediately before it.
std::cout << zipitr.template get<0>() << " " << zipitr.template get<1>() << std::endl;
// ^^^^^^^^ ^^^^^^^^
Read this answer for details of why this is needed.
An alternative that avoids the template keyword is to use the boost::get free function.
std::cout << boost::get<0>(zipitr) << " " << boost::get<1>(zipitr) << std::endl;
Your zip_range function can be simplified (or replaced) using boost::combine
#include <boost/range/combine.hpp>
template<class... Conts>
auto zip_range(Conts&... conts)
-> decltype( boost::combine(conts...) )
{
return boost::combine(conts...);
}
Live demo
The reason you can't pass {1,2,3} directly to zip_range is that a braced-init-list is not an expression, so it doesn't have a type, which means template argument deduction cannot work.
auto has a special rule to deal with them that allows it to deduce the type as std::initializer_list<T>, so the following works:
auto l1 = {1,2,3};
auto l2 = {4,5,6};
for ( auto const& zipitr : zip_range(l1,l2) ) {
std::cout << boost::get<0>(zipitr) << " " << boost::get<1>(zipitr) << std::endl;
}
Live demo

how to iterate through boost unordered_map?

I just want to iterate through the members of an unordered map.
There are many simple examples on the web, including on this site, and yet none of them will compile. Apparently some examples are from a previous non-standard STL version, some are just old, and some are so new that my gcc 4.7.2 can't handle them. Please do not suggest the new auto iterator from C++11. I will get there some day when all my libraries are validated for that. Until then, I just want the old one to work. (see below for what I have tried)
Here is my test code:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[]) {
boost::unordered::unordered_map<std::string,int> umap;
//can't get gcc to accept the value_type()...
//umap.insert(boost::unordered_map::value_type("alpha",1));
//umap.insert(boost::unordered_map::value_type("beta",2));
//umap.insert(boost::unordered_map::value_type("gamma",3));
umap["alpha"]=1; //this works
umap["beta"]=2;
umap["gamma"]=3;
//can't get gcc to compile the iterator
//for (boost::unordered_map::iterator it=umap.begin();it!=umap.end();++it)
// std::cout << it->first <<", " << it->second << std::endl;
//gcc does not like it this way either
//for (int x=0;x<umap.size();x++)
// std::cout << x << " : " << umap[x].first << " = " << umap[x].second << std::endl;
//will gcc take this? No it does not
//for (int x=0;x<umap.size();x++)
// std::cout << x << " : " << umap[x] << std::endl;
//this does not work
//boost::unordered::unordered_map::iterator<std::string,int> it;
//this does not work
//boost::unordered::unordered_map::iterator it;
//for (it=umap.begin();it!=umap.end();++it)
// std::cout << it->first <<", " << it->second << std::endl;
//this does not work
//BOOST_FOREACH(boost::unordered_map::value_type value, umap) {
// std::cout << value.second;
// }
//std::cout << std::endl;
//this does not work either
//BOOST_FOREACH(boost::unordered_map::value_type<std::string,int> value, umap) {
// std::cout << value.second;
// }
//std::cout << std::endl;
std::cout << "umap size: " << umap.size() << std::endl;
std::cout << "umap max size: " << umap.max_size() << std::endl;
std::cout << "find alpha: " << (umap.find("alpha")!=umap.end()) << std::endl;
std::cout << "count beta: " << umap.count("beta") << std::endl;
}
Most of the errors are a variation of this:
error: 'template<class K, class T, class H, class P, class A> class boost::unordered::unordered_map' used without template parameters
Here is my build command:
g++ -I..\boost umap.cpp
I should be embarrassed for getting stuck on such a beginner's question, but from the volume of similar questions I am finding, this is just hard enough to stop a lot of people in their tracks. I have written hash containers before (back when it was recommended NOT to use STL) and I am very tempted to just write my own... but the right thing to do is learn to use as many existing tools as possible... help!
I've looked at the following questions on stackoverflow where I haven't found an answer:
iterate through unordered_map using boost_foreach
I tried:
BOOST_FOREACH(boost::unordered_map::value_type& value, umap) {
but it gives the same error I show below.
Unordered_map iterator invalidation
This one is close, but not quite my issue:
Iterator invalidation in boost::unordered_map
This one uses auto
and I can't switch compilers at this time.
C++ some questions on boost::unordered_map & boost::hash
This one is mostly about the theory of maps:
how to use boost::unordered_map
This is a rather complicated example, but you will see in my code I am already trying to declare iterators... they just won't compile.
How to use BOOST_FOREACH with an Unordered_map?
This is a nice example, but
it just does not compile. I tried a version of this in my code.
IT WORKS !
Here is the working code:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[]) {
boost::unordered::unordered_map<std::string,int> umap;
umap["alpha"]=1;
umap["beta"]=2;
umap["gamma"]=3;
boost::unordered::unordered_map<std::string,int>::iterator it;
for (it=umap.begin();it!=umap.end();++it)
std::cout << it->first <<", " << it->second << std::endl;
std::cout << "umap size: " << umap.size() << std::endl;
std::cout << "umap max size: " << umap.max_size() << std::endl;
std::cout << "find alpha: " << (umap.find("alpha")!=umap.end()) << std::endl;
std::cout << "count beta: " << umap.count("beta") << std::endl;
}
It was a syntax error. I was putting the type in the wrong place when declaring the iterator.
Thanks everyone for your responses.
try changing boost::unordered::unordered_map::iterator it; it to boost::unordered::unordered_map<std::string,int>::iterator it;
NOTE:
It is also possible, and a good idea in more complex situations, to create a typedef of it, such as typedef boost::unordered::unordered_map<std::string,int>::iterator UMapStringIntIt;, or whatever you may call it.
The answer is in the question, but the simple solution is here for your convenience:
#include <iostream>
#include <boost/unordered_map.hpp>
#include <string>
int main(int argc,char *argv[])
{
boost::unordered::unordered_map<std::string,int> umap;
umap["alpha"]=1;
umap["beta"]=2;
umap["gamma"]=3;
for ( auto it= umap.begin(); it != umap.end(); ++it )
std::cout << it->first <<", " << it->second << std::endl;
}

Using a boost::fusion::map in boost::spirit::karma

I am using boost spirit to parse some text files into a data structure and now I am beginning to generate text from this data structure (using spirit karma).
One attempt at a data structure is a boost::fusion::map (as suggested in an answer to
this question). But although I can use boost::spirit::qi::parse() and get data in it easily, when I tried to generate text from it using karma, I failed.
Below is my attempt (look especially at the "map_data" type). After some reading and playing around with other fusion types, I found boost::fusion::vector and BOOST_FUSION_DEFINE_ASSOC_STRUCT. I succeeded to generate output with both of them, but they don't seem ideal: in vector you cannot access a member using a name (it is like a tuple) -- and in the other solution, I don't think I need both ways (member name and key type) to access the members.
#include <iostream>
#include <string>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/include/make_map.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/transform.hpp>
struct sb_key;
struct id_key;
using boost::fusion::pair;
typedef boost::fusion::map
< pair<sb_key, int>
, pair<id_key, unsigned long>
> map_data;
typedef boost::fusion::vector < int, unsigned long > vector_data;
#include <boost/fusion/include/define_assoc_struct.hpp>
BOOST_FUSION_DEFINE_ASSOC_STRUCT(
(), assocstruct_data,
(int, a, sb_key)
(unsigned long, b, id_key))
namespace karma = boost::spirit::karma;
template <typename X>
std::string to_string ( const X& data )
{
std::string generated;
std::back_insert_iterator<std::string> sink(generated);
karma::generate_delimited ( sink, karma::int_ << karma::ulong_, karma::space, data );
return generated;
}
int main()
{
map_data d1(boost::fusion::make_map<sb_key, id_key>(234, 35314988526ul));
vector_data d2(boost::fusion::make_vector(234, 35314988526ul));
assocstruct_data d3(234,35314988526ul);
std::cout << "map_data as_vector: " << boost::fusion::as_vector(d1) << std::endl;
//std::cout << "map_data to_string: " << to_string(d1) << std::endl; //*FAIL No 1*
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d1) << boost::fusion::at_c<0>(d1) << std::endl << std::endl;
std::cout << "vector_data: " << d2 << std::endl;
std::cout << "vector_data to_string: " << to_string(d2) << std::endl << std::endl;
std::cout << "assoc_struct as_vector: " << boost::fusion::as_vector(d3) << std::endl;
std::cout << "assoc_struct to_string: " << to_string(d3) << std::endl;
std::cout << "at_key (sb_key): " << boost::fusion::at_key<sb_key>(d3) << d3.a << boost::fusion::at_c<0>(d3) << std::endl;
return 0;
}
Including the commented line gives lots of pages of compilation errors, among which notably something like:
no known conversion for argument 1 from ‘boost::fusion::pair’ to ‘double’
no known conversion for argument 1 from ‘boost::fusion::pair’ to ‘float’
Might it be that to_string needs the values of the map_data, and not the pairs? Though I am not good with templates, I tried to get a vector from a map using transform in the following way
template <typename P>
struct take_second
{
typename P::second_type operator() (P p)
{
return p.second;
}
};
// ... inside main()
pair <char, int> ff(32);
std::cout << "take_second (expect 32): "
<< take_second<pair<char,int>>()(ff) << std::endl;
std::cout << "transform map_data and to_string: "
<< to_string(boost::fusion::transform(d1, take_second<>())); //*FAIL No 2*
But I don't know what types am I supposed to give when instantiating take_second and anyway I think there must be an easier way to get (iterate over) the values of a map (is there?)
If you answer this question, please also give your opinion on whether using an ASSOC_STRUCT or a map is better.
I think I noticed your question on the [spirit-general] list earlier.
It got 14 views there - and I did some fairly deep investigation. Sadly, to the best of my knowledge I don't think Spirit has any support for associate Fusion structures.
In fact, outside MSM and Phoenix, there was no place in boost where I see fusion::map being used.
Is there a chance you could just use std::map/std::pair instead? Here's a tiny proof of concept:
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted.hpp>
int main()
{
const auto data = std::map<std::string, double> {
{ "pi", 3.1415925 },
{ "e", 2.718281828 },
{ "Answer", 42 } };
namespace karma = boost::spirit::karma;
std::cout << karma::format((karma::string << " = " << karma::double_) % karma::eol, data)
<< std::endl;
}
Output:
Answer = 42.0
e = 2.718
pi = 3.142