Added (conditional) SFINAE support.

Better streamable detection for toString using SFINAE (falls back to non-SFINAE version without)
This commit is contained in:
Phil Nash 2013-04-16 22:55:31 +01:00
parent 243f2d2caf
commit 5062d3e92b
5 changed files with 180 additions and 10 deletions

View File

@ -0,0 +1,74 @@
/*
* Created by Phil on 15/04/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
// Much of the following code is based on Boost (1.53)
////////////////////////////////////////////////////////////////////////////////
// Borland
#ifdef __BORLANDC__
#if (__BORLANDC__ > 0x582 )
#define CATCH_SFINAE
#endif
#endif // __BORLANDC__
////////////////////////////////////////////////////////////////////////////////
// EDG
#ifdef __EDG_VERSION__
#if (__EDG_VERSION__ > 238 )
#define CATCH_SFINAE
#endif
#endif // __EDG_VERSION__
////////////////////////////////////////////////////////////////////////////////
// Digital Mars
#ifdef __DMC__
#if (__DMC__ > 0x840 )
#define CATCH_SFINAE
#endif
#endif // __DMC__
////////////////////////////////////////////////////////////////////////////////
// GCC
#ifdef __GNUC__
#if __GNUC__ < 3
#if (__GNUC_MINOR__ >= 96 )
#define CATCH_SFINAE
#endif
#elif __GNUC__ >= 3
#define CATCH_SFINAE
#endif // __GNUC__ < 3
#endif // __GNUC__
////////////////////////////////////////////////////////////////////////////////
// Visual C++
#ifdef _MSC_VER
#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
#define CATCH_SFINAE
#endif
#endif // _MSC_VER
#endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED

View File

@ -0,0 +1,44 @@
/*
* Created by Phil on 15/04/2013.
* Copyright 2013 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
// Try to detect if the current compiler supports SFINAE
#include "catch_compiler_capabilities.h"
#ifdef CATCH_SFINAE
namespace Catch {
struct TrueType {
static const bool value = true;
typedef void Enable;
char sizer[1];
};
struct FalseType {
static const bool value = false;
typedef void Disable;
char sizer[2];
};
template<bool> struct NotABooleanExpression;
template<bool c> struct If : NotABooleanExpression<c> {};
template<> struct If<true> : TrueType {};
template<> struct If<false> : FalseType {};
template<int size> struct SizedIf;
template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
} // end namespace Catch
#endif // CATCH_SFINAE
#endif // TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED

View File

@ -9,6 +9,8 @@
#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
#include "catch_common.h" #include "catch_common.h"
#include "catch_sfinae.hpp"
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <limits> #include <limits>
@ -18,6 +20,49 @@
#endif #endif
namespace Catch { namespace Catch {
#ifdef CATCH_SFINAE
namespace Detail {
template<typename T>
class IsStreamInsertableHelper {
template<int N> struct TrueIfSizeable : TrueType {};
template<typename T2>
static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
static FalseType dummy(...);
public:
typedef SizedIf<sizeof(dummy((T*)0))> type;
};
template<typename T>
struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
template<typename T>
void toStream( std::ostream& os, T const& value, typename IsStreamInsertable<T>::Enable* = 0 ) {
os << value;
}
template<typename T>
void toStream( std::ostream& os, T const&, typename IsStreamInsertable<T>::Disable* = 0 ) {
os << "{?}";
}
}
template<typename T>
struct StringMaker {
static std::string convert( T const& value ) {
std::ostringstream oss;
Detail::toStream( oss, value );
return oss.str();
}
};
#else
namespace Detail { namespace Detail {
struct NonStreamable { struct NonStreamable {
@ -40,6 +85,10 @@ struct StringMaker {
return oss.str(); return oss.str();
} }
}; };
#endif
template<typename T> template<typename T>
struct StringMaker<T*> { struct StringMaker<T*> {
static std::string convert( T const* p ) { static std::string convert( T const* p ) {
@ -57,7 +106,7 @@ struct StringMaker<std::vector<T> > {
std::ostringstream oss; std::ostringstream oss;
oss << "{ "; oss << "{ ";
for( std::size_t i = 0; i < v.size(); ++ i ) { for( std::size_t i = 0; i < v.size(); ++ i ) {
oss << v[i]; oss << toString( v[i] );
if( i < v.size() - 1 ) if( i < v.size() - 1 )
oss << ", "; oss << ", ";
} }
@ -83,7 +132,6 @@ namespace Detail {
template<typename T> template<typename T>
std::string toString( const T& value ) { std::string toString( const T& value ) {
return StringMaker<T>::convert( value ); return StringMaker<T>::convert( value );
// return Detail::makeString( value );
} }
// Built in overloads // Built in overloads

View File

@ -182,7 +182,7 @@ namespace ObjectWithConversions
"Operators at different namespace levels not hijacked by Koenig lookup" "Operators at different namespace levels not hijacked by Koenig lookup"
) )
{ {
Object o; Object o;
REQUIRE(0xc0000000 == o ); REQUIRE(0xc0000000 == o );
} }
} }
@ -337,14 +337,14 @@ TEST_CASE( "Assertions then sections", "" )
} }
} }
class Awkward struct Awkward
{ {
operator int() const { return 7; } operator int() const { return 7; }
}; };
//TEST_CASE( "non streamable", "" ) TEST_CASE( "non streamable", "" )
//{ {
// Awkward awkward; Awkward awkward;
// std::string s = Catch::toString( awkward ); std::string s = Catch::toString( awkward );
// REQUIRE( s == "{?}" ); REQUIRE( s == "7" ); // This is ambiguous without SFINAE
//} }

View File

@ -59,6 +59,8 @@
266ECD73170F3C620030D735 /* BDDTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BDDTests.cpp; path = ../../../SelfTest/BDDTests.cpp; sourceTree = "<group>"; }; 266ECD73170F3C620030D735 /* BDDTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BDDTests.cpp; path = ../../../SelfTest/BDDTests.cpp; sourceTree = "<group>"; };
266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_legacy_reporter_adapter.hpp; sourceTree = "<group>"; }; 266ECD8C1713614B0030D735 /* catch_legacy_reporter_adapter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch_legacy_reporter_adapter.hpp; sourceTree = "<group>"; };
266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_legacy_reporter_adapter.h; sourceTree = "<group>"; }; 266ECD8D1713614B0030D735 /* catch_legacy_reporter_adapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = catch_legacy_reporter_adapter.h; sourceTree = "<group>"; };
26759472171C72A400A84BD1 /* catch_sfinae.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_sfinae.hpp; sourceTree = "<group>"; };
26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_compiler_capabilities.h; sourceTree = "<group>"; };
26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = "<group>"; }; 26847E5B16BBAB790043B9C1 /* catch_message.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = catch_message.h; sourceTree = "<group>"; };
26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = "<group>"; }; 26847E5C16BBACB60043B9C1 /* catch_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch_message.hpp; sourceTree = "<group>"; };
26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = "<group>"; }; 26847E5D16BBADB40043B9C1 /* catch_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = catch_message.cpp; path = ../../../SelfTest/SurrogateCpps/catch_message.cpp; sourceTree = "<group>"; };
@ -395,6 +397,8 @@
4AEE0326161431070071E950 /* catch_streambuf.h */, 4AEE0326161431070071E950 /* catch_streambuf.h */,
4ACE21C8166CA19700FB5509 /* catch_option.hpp */, 4ACE21C8166CA19700FB5509 /* catch_option.hpp */,
2694A1F8169FFF9B004816E3 /* catch_line_wrap.h */, 2694A1F8169FFF9B004816E3 /* catch_line_wrap.h */,
26759472171C72A400A84BD1 /* catch_sfinae.hpp */,
26759473171C74C200A84BD1 /* catch_compiler_capabilities.h */,
); );
name = Infrastructure; name = Infrastructure;
sourceTree = "<group>"; sourceTree = "<group>";