Overloaded stream operators.

To avoid paying the huge penalty of including iostream and string for
users that don't need those headers, and to avoid creating a second,
optional header file, I resorted to defining the operators as templates
to prevent type checking until the user tries to actually use them. The
stream types and strings are wrapped in a metafunction that depends on
the template parameter. This is basically a hack, but it seems to work.
This commit is contained in:
Anton Bachin 2015-06-11 21:59:12 -05:00
parent 4314ad3fd3
commit 0f63667106
2 changed files with 81 additions and 0 deletions

52
enum.h
View File

@ -10,6 +10,7 @@
#include <cstddef>
#include <cstring>
#include <iosfwd>
#include <stdexcept>
@ -1038,4 +1039,55 @@ BETTER_ENUMS__CONSTEXPR inline bool operator !=(const Enum &a, const Enum &b) \
namespace better_enums {
// This template is used both as a sort of enable_if for SFINAE, and to delay
// the compiler from type-checking certain expressions. enum.h does not include
// <iostream> or <string>, because those headers parse very slowly. Therefore,
// it is necessary to prevent the compiler from trying to do anything with types
// from those headers unless the operators <<, >> are actually used, by which
// point the user is expected to have included <iostream> and/or <string>. The
// alternative is to simply move the operator definitions into a separate add-on
// header file.
//
// It should be possible to use std::enable_if, however <type_traits> is not
// available in C++98.
template <typename T, typename Enum>
struct hide { typedef T type; };
}
template <typename Enum>
inline typename better_enums::hide<std::ostream,
typename Enum::_enumerated>::type&
operator <<(std::ostream& stream, const Enum& value)
{
return stream << value._to_string();
}
template <typename Enum>
inline typename better_enums::hide<std::istream,
typename Enum::_enumerated>::type&
operator >>(typename better_enums::hide<std::istream, Enum>::type& stream,
Enum& value)
{
typedef typename better_enums::hide<std::ios_base, Enum>::type ios_base;
typedef typename better_enums::hide<std::string, Enum>::type string;
string buffer;
stream >> buffer;
better_enums::optional<Enum> converted =
Enum::_from_string_nothrow(buffer.c_str());
if (converted)
value = *converted;
else
stream.setstate(ios_base::failbit);
return stream;
}
#endif // #ifndef BETTER_ENUMS__ENUM_H

29
test/cxxtest/stream.h Normal file
View File

@ -0,0 +1,29 @@
#include <cxxtest/TestSuite.h>
#include <iostream>
#include <enum.h>
ENUM(Compiler, int, GCC, Clang, MSVC)
class StreamOperatorTests : public CxxTest::TestSuite {
public:
void test_output()
{
std::stringstream stream;
stream << +Compiler::GCC;
TS_ASSERT_EQUALS(strcmp(stream.str().c_str(), "GCC"), 0);
}
void test_input()
{
std::stringstream stream("Clang");
Compiler compiler = Compiler::GCC;
stream >> compiler;
TS_ASSERT_EQUALS(compiler, +Compiler::Clang);
}
};