diff --git a/include/internal/catch_sfinae.hpp b/include/internal/catch_sfinae.hpp index ef414f84..ccb6dba9 100644 --- a/include/internal/catch_sfinae.hpp +++ b/include/internal/catch_sfinae.hpp @@ -11,8 +11,6 @@ // Try to detect if the current compiler supports SFINAE #include "catch_compiler_capabilities.h" -#ifdef CATCH_SFINAE - namespace Catch { struct TrueType { @@ -26,6 +24,8 @@ namespace Catch { char sizer[2]; }; +#ifdef CATCH_SFINAE + template struct NotABooleanExpression; template struct If : NotABooleanExpression {}; @@ -35,10 +35,10 @@ namespace Catch { template struct SizedIf; template<> struct SizedIf : TrueType {}; template<> struct SizedIf : FalseType {}; + +#endif // CATCH_SFINAE } // end namespace Catch -#endif // CATCH_SFINAE - #endif // TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED diff --git a/include/internal/catch_tostring.hpp b/include/internal/catch_tostring.hpp index 0f7b8380..739dd851 100644 --- a/include/internal/catch_tostring.hpp +++ b/include/internal/catch_tostring.hpp @@ -20,11 +20,10 @@ #endif namespace Catch { +namespace Detail { #ifdef CATCH_SFINAE -namespace Detail { - template class IsStreamInsertableHelper { template struct TrueIfSizeable : TrueType {}; @@ -40,53 +39,47 @@ namespace Detail { template struct IsStreamInsertable : IsStreamInsertableHelper::type {}; - template - void toStream( std::ostream& os, T const& value, typename IsStreamInsertable::Enable* = 0 ) { - os << value; - } - - template - void toStream( std::ostream& os, T const&, typename IsStreamInsertable::Disable* = 0 ) { - os << "{?}"; - } - -} - -template -struct StringMaker { - static std::string convert( T const& value ) { - std::ostringstream oss; - Detail::toStream( oss, value ); - return oss.str(); - } -}; - #else -namespace Detail { + struct BorgType { + template BorgType( T const& ); + }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); - struct NonStreamable { - template NonStreamable( const T& ){} + template + struct IsStreamInsertable { + static std::ostream &s; + static T const &t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#endif + + template + struct StringMakerBase { + template + static std::string convert( T const& ) { return "{?}"; } + }; + + template<> + struct StringMakerBase { + template + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } }; } // end namespace Detail -// If the type does not have its own << overload for ostream then -// this one will be used instead -inline std::ostream& operator << ( std::ostream& ss, Detail::NonStreamable ){ - return ss << "{?}"; -} - template -struct StringMaker { - static std::string convert( T const& value ) { - std::ostringstream oss; - oss << value; - return oss.str(); - } -}; - -#endif +struct StringMaker : + Detail::StringMakerBase::value> {}; template diff --git a/projects/SelfTest/TrickyTests.cpp b/projects/SelfTest/TrickyTests.cpp index 0dd7c614..c79ad008 100644 --- a/projects/SelfTest/TrickyTests.cpp +++ b/projects/SelfTest/TrickyTests.cpp @@ -342,11 +342,9 @@ struct Awkward operator int() const { return 7; } }; -// This now works with GCC/ Clang usinh SFINAE -// Uncomment when it works on all compilers that are tested -//TEST_CASE( "non streamable", "" ) -//{ -// Awkward awkward; -// std::string s = Catch::toString( awkward ); -// REQUIRE( s == "7" ); // This is ambiguous without SFINAE -//} +TEST_CASE( "non streamable - with conv. op", "" ) +{ + Awkward awkward; + std::string s = Catch::toString( awkward ); + REQUIRE( s == "7" ); +}