限制cin.操作符到特定范围

restrict cin. operator to a specific range

本文关键字:范围 cin 操作符 限制      更新时间:2023-10-16

如果我想限制cin操作符的范围该怎么办?就像下面的代码一样,我从用户那里获取输入,现在输入必须小于100,即如果用户输入标记> 100,它应该报告一个错误消息。

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;
}

你可以尝试这样做:

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);

这将确保输入是一个有效的整数值且小于100,只有在输入了有效的输入后才终止循环。

一般操作:

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);
}

在你的代码中调用它:

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);

在这种情况下,稍微重载操作符可以隐藏可重用helper类中的复杂性:

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 lown";
            }
            else if (dest > the_limits.upper_limit) {
                std::cout << "Value too highn";
            }
            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 }; }

很乱,但是你可以简单地写:

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 */ }

您可以创建一个操纵符来为您做这些:

#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);
}

除了我的另一个答案之外,这里还有另一种设置范围的方法,但将语义合并到安装在流的区域设置中的std::num_get<facet>中。这有点复杂,但它覆盖了流提取整数的默认行为,并使用自定义范围检查代码:

#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;
}

你可以这样使用:

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...
}