Lo primero que necesitamos es una clase que nos permita "controlar" la entrada del teclado.
Para nuestra desgracia, el estándar de C++ no ayuda, ya que los mecanismos de entrada no van a devolver ningún dato hasta que el usuario presione la tecla "enter". Por este motivo nos tenemos que pegar con mecanismos menos portables... para la ocasión he usado la tan odiada "conio". Si alguien se lo quiere currar más está en su perfecto derecho.
El método run de la clase es bastante simple... cuando se presiona una tecla, activa un flag que indica la intención del usuario de introducir un número... cuando se introduce un carácter se actualiza el número introducido (esta versión no admite backspace)... cuando se introduce un enter se almacena el número y se sale de la función.
Código
class DataManager { public: DataManager( ) = default; DataManager( const DataManager& ) = delete; ~DataManager( ) = default; void Run( ) { int temp_number = 0; while ( true ) { char c = getch( ); _withData = true; if ( c != '\n' && c != '\r' ) { std::cout << c; temp_number *= 10; temp_number += c - '0'; } else { std::cout << std::endl; _number = temp_number; break; } } } bool WithData( ) const { return _withData; } int Number( ) const { return _number; } const DataManager& operator=( const DataManager& ) = delete; private: bool _withData = false; int _number = 0; };
Después necesitamos una clase para llevar de forma sencilla el conteo del tiempo... algo del tipo:
Código
class Timer { public: using milliseconds = std::chrono::milliseconds; Timer( ) { Reset( ); } Timer( const Timer& ) = delete; ~Timer( ) = default; void Reset( ) { _start = std::chrono::high_resolution_clock::now( ); } milliseconds Elapsed( ) const { return std::chrono::duration_cast< milliseconds >( std::chrono::high_resolution_clock::now( ) - _start ); } const Timer& operator=( const Timer& ) = delete; private: std::chrono::high_resolution_clock::time_point _start; };
Cuando se crea la clase se registra el tiempo y llamando a "Elapsed" se devuelve el número de milisegundos desde ese instante. Reset vuelve a inicializar la clase.
Con estos ingredientes ya tenemos casi todo el trabajo echo... solo nos falta mezclarlos convenientemente en el main:
Código
int main( ) { std::cout << "Introduce un numero." << std::endl; std::cout << "Tienes 5 segundos para empezar" << std::endl; DataManager manager; std::thread thread{ [](DataManager* mgr){ mgr->Run( ); }, &manager }; Timer timer; while ( timer.Elapsed( ) < std::chrono::seconds{ 5 } ) { if ( manager.WithData( ) ) break; } if ( !manager.WithData( ) ) thread.detach( ); else thread.join( ); if ( manager.WithData( ) ) std::cout << "Has introducido el numero: " << manager.Number( ) << std::endl; else std::cout << "No has introducido ningun numero." << std::endl; }
Para controlar la entrada del teclado se crea un hilo. Después se inicializa el temporizador y se mantiene una espera activa de 5 segundos. La idea del temporizador en vez de un sleep es para que la aplicación pueda responder instantáneamente si el usuario introduce el número antes de 5 segundos.
Pasado el tiempo de espera activa se comprueba si el usuario ha hecho al menos el amago de introducir un número... si es así entonces espera pacientemente a que el usuario termine de introducir el número... en caso contrario finaliza el hilo y muestra el mensaje correspondiente.
Como he comentado antes, es algo muy mejorable. El ejemplo lo he realizado a petición de vangodp y sirve solo con fines ilustrativos.
PD.: utiliza funciones propias de C++11, ojo con los compiladores no compatibles.