A contribution of my own.
This is a simple input class whose sole purpose is to reduce the amount of lines and work you need to do to acquire input from the console (via cin).
The class is made to work with both char and wchar_t, as well as any custom class that has an overloaded << operator.
The code is made to work with both exceptions and return values. The functions that return the value directly throws an exception if it goes wrong. The functions that take a reference to a variable to store to and returns a bool will not throw.
Dependencies:
- Boost
- C++ Standard Library
Source:
Code:
// Input.h
#ifndef INPUT_20081018_H
#define INPUT_20081018_H
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/integer_traits.hpp>
#include <Stuff/Traits.h>
namespace Stuff
{
template<typename CharT> struct InputTraits
{
static std::basic_ostream<char>& out_stream;
static std::basic_istream<char>& in_stream;
typedef std::string StorageType;
typedef typename boost::add_reference
<
typename boost::add_const<typename integer_traits<CharT>::BasicType>::type
>::type CharType;
};
template<typename CharT> std::basic_ostream<char>& InputTraits<CharT>::out_stream = std::cout;
template<typename CharT> std::basic_istream<char>& InputTraits<CharT>::in_stream = std::cin;
template<> struct InputTraits<const char*>: public InputTraits<char>
{
typedef const char* CharType;
};
template<> struct InputTraits<const wchar_t*>
{
static std::basic_ostream<wchar_t>& out_stream;
static std::basic_istream<wchar_t>& in_stream;
typedef std::wstring StorageType;
typedef const wchar_t* CharType;
};
std::basic_ostream<wchar_t>& InputTraits<const wchar_t*>::out_stream = std::wcout;
std::basic_istream<wchar_t>& InputTraits<const wchar_t*>::in_stream = std::wcin;
template<> struct InputTraits<wchar_t*>: public InputTraits<const char*> {};
template<> struct InputTraits<char*>: public InputTraits<const char*> {};
#ifdef UNICODE
typedef wchar_t* StrType_t;
#else
typedef char* StrType_t;
#endif
template<typename CharT = StrType_t, template<typename> class Traits = InputTraits> class CInput
{
private:
typedef Traits<CharT> Traits_;
public:
CInput() {}
CInput(CharT strInputQ)
{
*this << strInputQ;
}
template<typename Type> bool ask_and_get(CharT strInputQ, Type& Answer) // does not throw
{
ask(strInputQ);
return get(Answer);
}
template<typename Type> bool get(Type& Answer) // does not throw
{
try
{
Answer = boost::lexical_cast<Type>(m_Answer);
}
catch (boost::bad_lexical_cast)
{
return false;
}
return true;
}
CInput& operator << (typename Traits<CharT>::CharType rhs)
{
Traits<CharT>::out_stream << rhs;
return *this;
}
template<typename DstType> CInput& operator >> (DstType& rhs)
{
get_answer();
rhs = boost::lexical_cast<DstType>(m_Answer);
return *this;
}
private:
void get_answer()
{
std::getline(Traits_::in_stream, m_Answer);
}
typename Traits_::StorageType m_Answer;
};
}
#endif // INPUT_20081018_H
// Traits.h
#ifndef TRAITS_20081019_H
#define TRAITS_20081019_H
#include <boost/type_traits.hpp>
#include <stdint.h>
namespace Stuff
{
template<typename T> struct ParamType
{
typedef typename boost::remove_cv
<
typename boost::remove_const
<
typename boost::remove_pointer
<
typename boost::remove_reference<T>::type
>::type
>::type
>::type BasicType;
};
template<typename T> struct integer_traits: public boost::integer_traits<T>, public ParamType<T>
{
static const bool is_array = false;
static const uint32_t array_dimensions = 0;
};
template<typename T> struct integer_traits<T[]>: public boost::integer_traits<T>, public ParamType<T>
{
static const bool is_array = true;
static const uint32_t array_dimensions = 1;
};
}
#endif // TRAITS_20081019_H
The class works in 3 steps:
1) Print question to user (can be done manually).
2) Fetch answer from user (stored internally).
3) Validate input and return it to the program.
There are a few simple functions.
The empty constructor just constructs the object.
The second constructor executes step 1 & 2.
The function ask executes steps 1 & 2.
The function ask_and_get performs all 3 steps.
The function get performs step 3.
Example:
Code:
#include <Stuff/Input.h>
#include <iostream>
class foo;
template<typename T> std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, const foo& rhs);
class foo
{
public:
std::string x;
template<typename T> friend std::basic_ostream<T>& operator << <> (std::basic_ostream<T>& lhs, const foo& rhs);
};
template<typename T> std::basic_ostream<T>& operator << (std::basic_ostream<T>& lhs, const foo& rhs)
{
lhs << rhs.x;
return lhs;
}
int main()
{
foo f;
f.x = "Enter an integer: ";
Stuff::CInput<int> input;
int x;
while ( !input.ask_and_get(f, x) )
{
std::cout << "That is not an integer.\n";
}
std::cout << "You entered: " << x << "\nHave a nice day.\n";
}
Output:
Enter an integer: a
That is not an integer.
Enter an integer: ,
That is not an integer.
Enter an integer: 555
You entered: 555
Have a nice day.
Press any key to continue . . .
Criticism is welcome!