There is so much to respond to. How I love these little design chats :)
They give such a lot of feedback. I will not incorporate any more changes until I've decided at a proper design, by listening to feedback and incorporating it into my design.
Because of the usual approach - read a string, convert it to appropriate type. If it fails, there is no need to clear the stream or other complications. It's my preferred method of doing inputs.
Originally Posted by phantomotap
I don't know. I don't see how I would place it all inside different classes and still maintain the easy solution of use for a (single) object.
Why make one class responsible for so much work?
Although you do give me the sense that there can be several versions of the input class, each tailored to a somewhat different approach.
The prompt could be of any type, so long as it can be outputted by an appropriate stream. That, too, could be changed, though, if one provided custom traits.
Why use a simple string as an argument related to prompting a user for input?
For error, a function or functor or an error message could be passed, depending on the design. That is my planning.
Why use a simple string as an argument related to providing an error message?
The code is not perfect here, either, of course.
Why does the error message appear unrelated to the validation function?
Either it should output an error and do the input process over or it should call a functor or function that handles the error process and probably starting the process over again.
You want to put the conversion and validation process as part of separate class(es)? IS that what you mean or did you have something else in mind?
Why not decouple this "dumb user handler" class mechanic from types and constructs not necessarily related to input and output?
I don't know what expression templates are, so no, unfortunately...
Have you studied many of the applications of expression templates?
Originally Posted by citizen
What I meant is as in your example. You read the input. Then you begin to validate it. You find out that it doesn't cut the requirements, so you ask again.
Originally Posted by CornedBee
So instead of typing ask(msg, error, ...) all the time, you could bind those things at the time of creation. Then all you would have to do is call ask().
I don't know if it has many advantages, it just seems natural to me that an object should be able to do that. In sense that it may be a someone whom you task for getting input: say this, and the answer you get must conform to these requirements. And then later you can say: ask again.
Generally, it does, but what if I want the answer to be no less than 1 or greater than 3? I have to check manually, but I want to be able to pass this off to the input validation, if possible.
Often the extraction operator does all three of these:
- Convert std::tstring to T.
- Validate input.
- Store input.
In particular, if the conversion from string to T is valid then the input is valid. Granted this is not necessarily the case for all extractors, but a number of them. Why doesn't that fit into your rationale?
Perhaps you may have some other exotic requirements, as well, mostly with custom classes. I think this applies mostly to built-in types, I suppose.
I don't know. It seemed more natural to make the class the actual answer itself.
>> This will eliminate the need for a separate variable for each answer, aside from the inputter and gives a greater feel for the class <<
I wanted to respond to this first. Why is that a good thing? C++ programmers are quite comfortable with the concept of streams and extracting individual datum from them. Any reason for going against the grain?
I can do either way, though.
I realize that all uses may not be the same, and as such, you need great control over what happens. The original idea was to remove repeating code, by placing the work inside a class and building a flexible but easy interface.
>> Now, if I had to type this on many occasions, I felt it was too much, too much general code that I had to re-type over and over. So why not provide a generic way to solve this? <<
Because not all I/O operations are interactive? Because input and output are fundamental parts of the problem-solving process and there are a diverse number of problems? I agree that you can abstract away a lot of the repetitive solutions, (see the proposed procedure as an example - if you ever agree they in fact "cut it" at some point) which is why I don't outright bash the attempt. I just never agreed with the design, and you asked for my opinion. Perhaps it's my inexperience talking but I have to resolve I/O program by program at this point because they're all somewhat different. I feel like I'm changing horses midstream and I apologize to readers who might be confused.
That is the very reason I want to provide more control over how it works, to customize certain steps of the way without the need to specialize a lot of template classes for many types, and preferably also not having to derive the class, though that could be a solution, too.
I want to create a piece of code that can easily incorporate and simplify the input process, so you don't have to repeat code all over the place. With specialized functors and stuff, it could be a simple way of customizing the class for different uses over many projects. That's how I feel.
I do feel the same, and I believe it will have advantages, if only for myself.
I feel as though you are trying to design an all-encompassing solution to interactive input, but at the moment I do not see how this saves me any work apart from the fact that I would not need to use control structures if I used an inputter instead. Let me tell you that the solution with control structures is easier to document, debug, and maintain--especially for other C++ programmers.
As to the maintain and understanding part... If you provide functors that validate your inputer, pretty much all you would not need is a loop. Less typing, less lines. And I feel it is no different from using an algorithm to perform tasks (such as std::for_each instead of a for loop).
Of course, some may like this, and some may not. That is why I also want to give control to the programmer to use it as they see naturally. I don't know if this is a bad idea.
The idea is that you can or can not have the validation inside the class. All it can do for you, if you want, is get the input, convert and store it. You can then retrieve it and validate it on your own.
Well, I found it easier to use a more abstract way instead of a way after retrieving the input. But you might just as well just a big number of If statements, if you wish.
You probably agree, since if I wanted to extend this class for any complicated data type then I need to abstract away validation methods and shove them in your class somehow ...
The function actually gave me something to think about, but the more I do think about it, the more I seem to think it does not cut the problem, from my view. Especially not if I go on to make it work in a different number of ways. Flexibility is always the key in C++!
>> This is not Java, so everything that is not an object does not have to be a class. <<
To wit, everything which is an object is an instantiation of a class by definition.
With all the problems class design seems to have in regards to the problem I cannot agree that it is the best route to take. Part of what makes C++ nice is that you can solve it naturally.