0

I'm writing a simple, universal function that shows a dialog. I intend to call it from different places in my code. The problem is that I need to clear the input buffer at the beginning of the function so lingering data from previous input is not interpreted as an answer.

This has to be a pretty common think to do, so I believe that C++ standard library provide some function that does that. However, I haven't any luck in finding it.

Here is a practical example of what I want to accomplish:

#include <iostream>
#include <string>

unsigned dialog(const char question[], const char answers[])
{
    //TODO reset std::cin
    while (true)
    {
        std::cout << question << " [";
        for (unsigned i = 0; answers[i] != '\0'; ++i)
        {
            if (i != 0)
                std::cout << '/';
            std::cout << answers[i];
        }
        std::cout << ']' << std::endl;
        std::string line;
        std::getline(std::cin, line);
        if (line.empty())
        {
            for (unsigned i = 0; answers[i] != '\0'; ++i)
                if (answers[i] >= 'A' && answers[i] <= 'Z')
                    return i;
        } else if (line.length() == 1)
        {
            const char answer = toupper(line[0]);
            for (unsigned i = 0; answers[i] != '\0'; ++i)
                if (answer == toupper(answers[i]))
                    return i;           
        }
    }
}

int main()
{
    // --- optional part ---
    std::cout << "Write something to clutter the input buffer..." << std::endl;
    std::string foo;
    std::cin >> foo; //User enters "aaa bbb ccc"
    // --- optional part end ---
    return dialog("Do you like this question?", "Yn");
}

interactive version

Unlike this other similar question, I'm looking for some portable solution. It should be supported in at least Windows and any Linux system.

There is also this question that is very similar to mine. However, all the answers seems to assume that input buffer is not empty at the moment. If I put it before my dialog and the input is empty at the moment (e.g. directly after start of the program), it leads to a situation when user needs to press Enter to even display my dialog on screen. A few answer from that question that don't assume that buffer is not empty, base on functions that depend on implementation of the standard library.

Piotr Siupa
  • 3,929
  • 2
  • 29
  • 65
  • @DavidZ The code there is ridiculously long and it doesn't seem to be portable. – Piotr Siupa Jan 20 '18 at 23:21
  • Sure, but that other question appears to be asking the same thing as you are. That makes it a duplicate. If you want to ask something different from what that other question is asking - for example, if you need a portable solution while the other question didn't - then you can edit this question accordingly and that might make it not a duplicate. – David Z Jan 20 '18 at 23:23
  • @DavidZ Done. Thanks for the explanation. – Piotr Siupa Jan 20 '18 at 23:29
  • No problem. I took the liberty of improving your phrasing there, to remove "EDIT" (which shouldn't be used in SO posts) and to explicitly link to the previous question to show what it's not a duplicate of. If you don't like my change you're welcome to revert it or change it further, of course, but I think this improves your chances of having the question not marked as a duplicate. – David Z Jan 20 '18 at 23:32
  • You should be able to remove all the previous input from `std::cin` buffer by clearing the stream state flags and then ignoring the rest of whatever is left in the buffer [like this](https://stackoverflow.com/questions/257091/how-do-i-flush-the-cin-buffer) – Justin Randall Jan 20 '18 at 23:32
  • @JustinRandall That looks like it should be an answer, not a comment (you could either post it to the other question or wait for this to be reopened). On another note, here is another related question that might have useful information: https://stackoverflow.com/questions/23713346/clear-the-cin-buffer-before-another-input-request-c?rq=1 – David Z Jan 20 '18 at 23:34
  • @JustinRandall I've seen that question but any of the answers doesn't seem to work for me. They either assumes... Actually, I'll put that into the question. Jeez, I'm bad in including all the relevant information. – Piotr Siupa Jan 20 '18 at 23:37
  • @DavidZ I'll put it as an answer if it ever gets reopened. OP says that it didn't work for them though... try `std::cin.sync();` instead then. – Justin Randall Jan 21 '18 at 00:00
  • @NO_NAME No worries, that's why we have the ability to edit. It's common for a question to go through a few (2-3, occasionally more) rounds of revision before it becomes fully polished. You're doing exactly the right thing by editing here. – David Z Jan 21 '18 at 00:02
  • @JustinRandall `std::cin.sync();` doesn't seem to do anything - http://cpp.sh/2ywq – Piotr Siupa Jan 21 '18 at 00:05
  • @NO_NAME I am intrigued by this. The only thing I got to work was flushing it out with a getline call. Try this. `std::string flushInput; std::getline(std::cin, flushInput);` – Justin Randall Jan 21 '18 at 00:31
  • @JustinRandall The problem with this solution is that is assumes that input buffers is not empty. This is the situation that I've described in the last paragraph. To see the problem, remove the optional code from my main function and see what happens then. – Piotr Siupa Jan 21 '18 at 00:38
  • @NO_NAME So then you just need to check if the input buffer has anything in it or not before you flush it? You can do that with `std::cin.seekg(0, std::cin.end); int length = std::cin.tellg(); std::cin.clear(); if (length > 0) { std::string flushInput; std::getline(std::cin, flushInput); }` – Justin Randall Jan 21 '18 at 00:57
  • @JustinRandall I think that you should write it as an answer. EDIT: Oh wait, you can't because the duplicate thing. – Piotr Siupa Jan 21 '18 at 01:00
  • @JustinRandall I've pasted this to cpp.sh It doesn't work unless I did something wrong :-( - http://cpp.sh/4gz4 – Piotr Siupa Jan 21 '18 at 01:05
  • @NO_NAME nope I'm wrong, apparently you can not seek on cin at all. Length is always -1 and the fail bit is always set on the stream. Seems like the only workable solution requires user to hit a key before your banner comes up. – Justin Randall Jan 21 '18 at 01:39
  • @JustinRandall From the point of user experience this is not a valid solution. That is exactly what I'm trying to avoid. Well, thanks for trying to answer. – Piotr Siupa Jan 21 '18 at 01:42

0 Answers0