Reputation:
what if i wanted to limit the range of cin operator? something like the code below, where i take the input from the user, now the input must be less than 100 i.e. if the user enters marks > 100 it should report an error message.
using namespace std;
void GetInput(const std::string &prompt, int &i, int max)
{
bool valid = false;
do
{
cout << prompt;
if (cin >> i && i < max)
{
valid = true;
}
else
{
cout << "Error: Input must be less than " << max << "." << endl;
}
} while (!valid);
}
class Marks
{
private:
int elec, prog, math, perc = NULL;
public:
void input()
{
cout << "enter the marks obtained in Mathematics = ";
cin >> math;
cout << "enter the marks obtained in Programming = ";
cin >> prog;
cout << "enter the marks obtained in Electronics = ";
cin >>elec;
}
void avg()
{
double avg = NULL;
avg = (math + prog + elec) / 3;
cout << "Average = " << avg << endl;
}
void Perc()
{
perc = ((math + elec + prog)*100) / 300;
cout << "The Percentage = " << perc <<" %"<< endl;
}
void grade()
{
if (perc >= 79)
{
cout << "A" << endl;
}
else if ((perc > 66) && (perc < 80))
cout << "B" << endl;
else if (perc < 66)
cout << "C" << endl;
}
};
int main(void)
{
Marks m;
int maths, prog, elec;
GetInput("enter the marks obtained in Mathematics = ", maths, 100);
GetInput("enter the marks obtained in Programming = ", prog, 100);
GetInput("enter the marks obtained in Electronics = ", elec, 100);
m.Perc();
m.avg();
m.grade();
system("PAUSE");
return 0;
}
Upvotes: 1
Views: 1691
Reputation: 96810
In addition to my other answer, here's another way to set a range but incorporate the semantics into std::num_get<facet>
installed in the stream's locale. It's a bit more complicated, but it overrides the stream's default behavior for extracting integers and uses the custom range checking code:
#include <iostream>
#include <utility>
int input_range() { static int idx = std::ios_base::xalloc(); return idx; }
void erase_range(std::ios_base::event evt, std::ios_base& str, int index)
{
if (evt == std::ios_base::erase_event)
{
delete static_cast<std::pair<int, int>*>(str.pword(index));
}
}
class num_get : public std::num_get<char>
{
public:
iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const
{
long temp;
in = std::num_get<char>::do_get(in, end, str, err, temp);
if (in != end)
err |= std::ios_base::failbit;
void*& p = str.pword(input_range());
if (p)
{
auto values = *static_cast<std::pair<int, int>*>(p);
if (!(values.first <= temp && temp <= values.second))
{
err |= std::ios_base::failbit;
} else
v = temp;
}
return in;
}
};
template<int I, int J>
std::istream& set_range(std::istream& is)
{
void*& p = is.pword(input_range());
erase_range(std::ios_base::erase_event, is, input_range());
if (is)
{
p = new std::pair<int, int>(I, J);
if (!dynamic_cast<const num_get*>(
&std::use_facet<std::num_get<char>>(is.getloc())))
{
is.imbue(std::locale(is.getloc(), new num_get));
is.register_callback(&erase_range, input_range());
}
}
return is;
}
You can use it like this:
void input()
{
std::cin >> set_range<0, 100>;
std::cout << "enter the marks obtained in Mathematics = ";
if (!(std::cin >> maths))
std::cout << "Error!";
std::cout << "enter the marks obtained in Programming = ";
// so on...
std::cout << "enter the marks obtained in Electronics = ";
// and so forth...
}
Upvotes: 0
Reputation: 96810
You can create a manipulator that does this for you:
#include <iostream>
template<int, int>
struct input_range_impl
{
input_range_impl(int& val) : val_(val)
{
}
template<int I, int U>
friend std::istream& operator>>(std::istream&, const input_range_impl<I, U>&);
private:
int& val_;
};
template<int I, int U>
std::istream& operator>>(std::istream& is, const input_range_impl<I, U>& manip)
{
if (!(is >> manip.val_) || !(I <= manip.val_ && manip.val_ >= U))
is.setstate(std::ios_base::failbit);
return is;
}
template<int I, int U>
input_range_impl<I, U> input_range(int& val)
{
return { val };
}
void input()
{
std::cout << "enter the marks obtained in Mathematics = ";
std::cin >> input_range<0, 100>(maths);
std::cout << "enter the marks obtained in Programming = ";
std::cin >> input_range<0, 100>(prog);
std::cout << "enter the marks obtained in Electronics = ";
std::cin >> input_range<0, 100>(elec);
}
Upvotes: 0
Reputation: 283713
In this case, a bit of operator overloading can hide the complexity in a reusable helper class:
template<typename TMin, typename TMax>
struct unbound_limit_range
{
const TMin lower_limit;
const TMax upper_limit;
};
template<typename TMin, typename TMax>
class bound_limit_range
{
std::istream& the_stream;
const unbound_limit_range<TMin, TMax> the_limits;
public:
bound_limit_range(istream& p_stream, const unbound_limit_range<TMin, TMax>& p_limits)
: the_stream(p_stream), the_limits(p_limits)
{}
template<typename TVar>
istream& operator>>(T& dest)
{
while (true) {
if (!(the_stream >> dest)) return the_stream;
if (dest < the_limits.lower_limit) {
std::cout << "Value too low\n";
}
else if (dest > the_limits.upper_limit) {
std::cout << "Value too high\n";
}
else {
return the_stream;
}
std::cout << "Try again: " << std::flush;
}
}
};
template<typename TMin, typename TMax>
bound_limit_range<TMin, TMax> operator>>(std::istream& stream, const limit_range<TMin, TMax>& limits) { return { stream, limits }; }
template<typename TMin, typename TMax>
unbound_limit_range<TMin, TMax> limit_range(TMin lower, TMax upper) { return { lower, upper }; }
Quite a mess, but then you can simply write:
cout << "enter the marks obtained in Mathematics = ";
cin >> limit_range(0, 100) >> maths;
cout << "enter the marks obtained in Programming = ";
cin >> limit_range(0, 100) >> prog;
cout << "enter the marks obtained in Electronics = ";
cin >> limit_range(0, 100) >> elec;
if (cin) { /* all succeeded */ }
Upvotes: 0
Reputation: 538
You could try something like this:
int maths;
bool valid = false;
do
{
cout << "Enter the marks obtained in Mathematics = ";
if (cin >> maths && maths < 100)
{
valid = true;
}
else
{
cout << "Error: Input must be less than 100." << endl;
}
} while (!valid);
This will ensure that the input is both a valid integer value and less than 100, only terminating the loop once valid input has been entered.
To do it generically:
void GetInput(const std::string &prompt, int &i, int max)
{
bool valid = false;
do
{
cout << prompt;
if (cin >> i && i < max)
{
valid = true;
}
else
{
cout << "Error: Input must be less than " << max << "." << endl;
}
} while (!valid);
}
And to call it in your code:
int maths, prog, elec;
GetInput("enter the marks obtained in Mathematics = ", maths, 100);
GetInput("enter the marks obtained in Programming = ", prog, 100);
GetInput("enter the marks obtained in Electronics = ", elec, 100);
Upvotes: 1