Thread: Input class project (again)

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654

    Input class project (again)

    I'm looking at the input class project again, reviving it...
    But at the moment, I am not sure sure of how to implement it and where.
    These are the features that I am looking for:
    - Able to ask a question.
    - Able to fetch input and convert to correct type.
    - Able to print a try again and retry if input is in bad format.
    - Support wide strings and streams (as well as "default").
    - Able to perform the ability to do input validation.
    - Flexibility.
    - Scalability.

    Thus, it should be the work of two or max three lines for each input request.
    It should be a variable to store the input (unless the input class/function stores it internally). The second should be a function call or a creating of a class instance. The third would probably be fetching or extracting the input with a stream operator or something.

    It might look like:
    Code:
    int x;
    GetInput<int>("Enter an integer: ", "That is not an integer. Try again.",
        "Integer must be larger than 10 and lesser than 20.",
        [](int x) -> bool { return x > 10 && x < 20; }, x);
    Or:
    Code:
    int x;
    CInput<int> input("Enter an integer: ", "That is not an integer. Try again.",
        "Integer must be larger than 10 and lesser than 20.",
        [](int x) -> bool { return x > 10 && x < 20 }); 
    input >> x;
    Goal:
    To make sure there are as few lines as possible each time input is required.

    Thoughts:
    - Should it be a class or a function? The biggest drawback with functions that I see is that they do not support default template arguments, nor can they store input (though that may not be necessary).
    - If it shall be a class, what goes into the class and what becomes utility functionality?
    - Where should utility functionality reside? In a class or a function?

    I would like to hear everyone's thoughts. I cannot seem to be able to separate this myself.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    i had to do something somewhat similar in implementing the secs II machine-to-machine interface.

    the two primary differences were that i read the input off of a TCP buffer, and i had to deduce the type from a format code in the upper 6 bits of the first byte of the message. if you use the format code, then you don't have to know the type apriori, and you can use it in a factory function.

    Code:
    const unsigned char fcList = 0;
    const unsigned char fcBinary = 8;
    const unsigned char fcBool = 9;
    const unsigned char fcASCII = 16;
    const unsigned char fcString = 16;
    const unsigned char fc2BChar = 17;
    const unsigned char fcInt64 = 24;
    const unsigned char fcInt8 = 25;
    const unsigned char fcInt16 = 26;
    const unsigned char fcInt32 = 28;
    const unsigned char fcFloat64 = 32;
    const unsigned char fcDouble = 32;
    const unsigned char fcFloat32 = 36;
    const unsigned char fcFloat = 36;
    const unsigned char fcUInt64 = 40;
    const unsigned char fcUInt8 = 41;
    const unsigned char fcUInt16 = 42;
    const unsigned char fcUInt32 = 44;
    
    secs2MsgData secs2MsgFactory(char *message)
    {
            const unsigned char fc = ((message[0]>>2)&0x3F);
            switch(fc)
            {
                    case fcList:
                            return secsList(message);
                    case fcBinary:
                            return secs2MsgItem<void *>(message);
                    case fcBool:
                            return secs2MsgItem<bool>(message);
                    case fcASCII:
                            return secs2MsgItem<String>(message);
    /*
                    case fcwchar:
                            return secs2MsgItem<wchar_t>(message);
    
    not actually supported; just a placeholder
    */
                    case fcInt64:
                            return secs2MsgItem<__int64>(message);
                    case fcInt8:
                            return secs2MsgItem<__int8>(message);
                    case fcInt16:
                            return secs2MsgItem<__int16>(message);
                    case fcInt32:
                            return secs2MsgItem<__int32>(message);
                    case fcDouble:
                            return secs2MsgItem<double>(message);
                    case fcFloat:
                            return secs2MsgItem<float>(message);
                    case fcUInt64:
                            return secs2MsgItem<unsigned __int64>(message);
                    case fcUInt8:
                            return secs2MsgItem<unsigned __int8>(message);
                    case fcUInt16:
                            return secs2MsgItem<unsigned __int16>(message);
                    case fcUInt32:
                            return secs2MsgItem<unsigned __int32>(message);
            }
            throw Exception("Invalid Format Code: "+(String)fc+" in message: "+message);
    
    }
    that's all i got. good luck.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Eh, I don't see remotely how it is similar to what I am trying to accomplish.
    I have an old version lying around (input class is the thread title).
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    *shrug* ok then.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Oh well, it's the thought that counts, eh?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    3735928559
    Join Date
    Mar 2008
    Location
    RTP
    Posts
    838
    i thought i would at least try to offer up something since your turning me on to doxygen has already saved me literally hundreds of manhours!

    if you want to expand it to a machine-to-machine input class, it might be relevant at some point.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It might be one of the goals due to flexibility and scalability, but right now there are no plans for such a thing...
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    I'd say allow it to use function pointers as a bounds tester. Would make more sense to me. Just my personal preferences but I think the variable you're streaming should be passed by reference (or pointer if you wish) and be the first parameter to the function. Could perhaps have it work with files streams too... Though how to handle errors would be worth considering.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    - Should it be a class or a function? The biggest drawback with functions that I see is that they do not support default template arguments, nor can they store input (though that may not be necessary).
    I think that one or two function templates will do. You would probably want one version to read without a range check while another version would perform a range check.

    One potential problem would be the reading in of strings: read using operator>> or using std::getline()?

    Quote Originally Posted by Elysia
    - Where should utility functionality reside? In a class or a function?
    To some extent this is utility functionality: it will complement the existing I/O stream and string functionality by providing convenience functions for input from the command prompt.

    Quote Originally Posted by twomers
    I'd say allow it to use function pointers as a bounds tester.
    That should not be a problem once a template parameter is used. Both function pointers and function objects could be passed in that case.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Bear in mind as well that you may want a flexible "range-check" for when the valid values aren't simply a min <= x <= max, where a user-function is called with the value. This way, you can cope with just about ANY input validation - in past projects I have done "dialog box editing" input validation, where it's VERY handy to have the choice of one or both of:
    1. Range check.
    2. Call a free function that validates my input.

    A typical case would be where the input value must match something in a database or list of "valid stuff" (think validating a user-id number).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    So I think the main question is right now? Class or function?
    I do not think a function has what it takes for the flexibility and scalability I am considering.

    Quote Originally Posted by twomers View Post
    Just my personal preferences but I think the variable you're streaming should be passed by reference (or pointer if you wish) and be the first parameter to the function.
    Yeah, that's easy to add / fix later. I actually forgot it in the original post, so I just added it to the end as an edit. But I do think it would be better as the first parameter, yes.

    Could perhaps have it work with files streams too... Though how to handle errors would be worth considering.
    Absolutely! This is one of the goals of the project: scalability.
    That is why I am strongly considering a class. Then it could be derived and the needed functionality added.

    Quote Originally Posted by laserlight View Post
    I think that one or two function templates will do. You would probably want one version to read without a range check while another version would perform a range check.
    That reminds me, yes... I would have to do overloading to make certain functionality as input checking optional. Another drawback to functions.

    One potential problem would be the reading in of strings: read using operator>> or using std::getline()?
    My approach would be std::getline & boost::lexical_cast, but as I mentioned, I want flexibility, so this behavior should be able to to be overriden.
    The way I see to do that is multiple functions that can be specialized, which might not be the best choice, or make it a class and make it derivable.

    That should not be a problem once a template parameter is used. Both function pointers and function objects could be passed in that case.
    Yes, a template parameter is what I am considering. Anything that supports operator (), returns bool and takes one argument of type T would do the trick.

    Quote Originally Posted by matsp View Post
    Bear in mind as well that you may want a flexible "range-check" for when the valid values aren't simply a min <= x <= max, where a user-function is called with the value. This way, you can cope with just about ANY input validation - in past projects I have done "dialog box editing" input validation, where it's VERY handy to have the choice of one or both of:
    1. Range check.
    2. Call a free function that validates my input.

    A typical case would be where the input value must match something in a database or list of "valid stuff" (think validating a user-id number).

    --
    Mats
    Yes, they thought has always been in my mind. If input validation is to be performed, it will be with a call to a function that takes the input as argument and returns a bool.
    I could also make a number of predefined functions available, for range checking, for example.
    Last edited by Elysia; 01-01-2009 at 04:21 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Elysia View Post
    Yes, they thought has always been in my mind. If input validation is to be performed, it will be with a call to a function that takes the input as argument and returns a bool.
    I could also make a number of predefined functions available, for range checking, for example.
    Yes, that's a possibility.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Elysia
    So I think the main question is right now? Class or function?
    I do not think a function has what it takes for the flexibility and scalability I am considering.
    Yes, it is possible that policy based programming techniques could be appropriate here. Unfortunately I am not well versed on the topic and I better be going to sleep now
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    So if I do make it a class, that only leaves the question of how it should act!
    Since it supplements, or acts as a utility, to streams, perhaps it should act and try to be one?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I still think the function as I presented it in one of your old threads is perfectly sufficient. You may want more than one overload, though.
    Code:
    template <typename T, typename Char, typename Traits, typename Validator>
    bool read(std::basic_istream<Char, Traits>& rstream, T& t, Validator validator)
    {
      try {
        std::basic_string<Char, Traits> buf;
        std::getline(rstream, buf);
        if(!rstream) return false;
        t = boost::lexical_cast<T>(buf);
        return validator(t);
      } catch(boost::bad_lexical_cast&) {
        return false;
      }
    }
    
    template <typename T, typename Char, typename Traits, typename Alloc, typename Validator>
    T ask(std::basic_ostream<Char, Traits>& wstream, std::basic_istream<Char, Traits>& rstream,
          const std::basic_string<Char, Traits, Alloc>& question,
          const std::basic_string<Char, Traits, Alloc>& failure, Validator validator)
    {
      T t;
      while(wstream << question, !read(istream, t, validator)) {
        wstream << failure;
      }
      return t;
    }
    
    template <typename T, typename Validator>
    inline T ask(const std::string& question, const std::string& failure, Validator validator)
    {
      return ask(std::cout, std::cin, question, failure, validator);
    }
    
    template <typename T, typename Validator>
    T ask(const std::wstring& question, const std::wstring& failure, Validator validator)
    {
      return ask(std::wcout, std::wcin, question, failure, validator);
    }
    
    // Example usage:
    std::unordered_set<Beer> goodBeers{ottakringer, stiegl, hadmar};
    Beer beer = ask<Beer>("Gimme a beer!\n", "That's'a not a good beer!\n",
      [&](const Beer& beer) -> bool { return goodBeers.find(beer) != goodBeers.end(); });
    It doesn't get any simpler, and I don't see a use for more flexibility or extensibility. If you really want, you can replace the getline-lexical_cast sequence with another functor, but I just don't see the point.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. deriving classes
    By l2u in forum C++ Programming
    Replies: 12
    Last Post: 01-15-2007, 05:01 PM
  3. Trouble with a lab
    By michael- in forum C Programming
    Replies: 18
    Last Post: 12-06-2005, 11:28 PM
  4. Creating class object from user input?
    By Munkey01 in forum C++ Programming
    Replies: 8
    Last Post: 01-05-2003, 10:09 AM
  5. My final project for programming class...
    By Leeman_s in forum C++ Programming
    Replies: 3
    Last Post: 12-20-2001, 04:34 PM