From bc0da4c31957c1f42ae1bc5bff50eac211d564a0 Mon Sep 17 00:00:00 2001 From: mat007 Date: Sat, 12 Mar 2011 09:45:45 +0000 Subject: [PATCH] Reworked logging git-svn-id: https://svn.code.sf.net/p/turtle/code/trunk@254 860be788-9bd5-4423-9f1e-828f051e677b --- build/vc80/turtle.vcproj | 16 +-- build/vc80/turtle_test.vcproj | 16 +-- src/libraries/turtle/check.hpp | 18 +-- src/libraries/turtle/constraints.hpp | 12 +- src/libraries/turtle/function.hpp | 4 +- .../{is_formattable.hpp => is_loggable.hpp} | 28 ++-- src/libraries/turtle/is_serializable.hpp | 2 +- src/libraries/turtle/{format.hpp => log.hpp} | 47 ++++--- src/libraries/turtle/operators.hpp | 12 +- src/libraries/turtle/sink.hpp | 24 ---- src/libraries/turtle/yes_no_type.hpp | 2 +- src/tests/turtle_test/is_formattable_test.cpp | 49 ------- src/tests/turtle_test/is_loggable_test.cpp | 54 ++++++++ .../{format_test.cpp => log_test.cpp} | 123 +++++++++++++++--- 14 files changed, 237 insertions(+), 170 deletions(-) rename src/libraries/turtle/{is_formattable.hpp => is_loggable.hpp} (59%) rename src/libraries/turtle/{format.hpp => log.hpp} (66%) delete mode 100644 src/libraries/turtle/sink.hpp delete mode 100644 src/tests/turtle_test/is_formattable_test.cpp create mode 100644 src/tests/turtle_test/is_loggable_test.cpp rename src/tests/turtle_test/{format_test.cpp => log_test.cpp} (57%) diff --git a/build/vc80/turtle.vcproj b/build/vc80/turtle.vcproj index 2db2e54..5208767 100644 --- a/build/vc80/turtle.vcproj +++ b/build/vc80/turtle.vcproj @@ -184,10 +184,6 @@ RelativePath="..\..\src\libraries\turtle\expectation.hpp" > - - @@ -197,11 +193,11 @@ > + + @@ -236,10 +236,6 @@ RelativePath="..\..\src\libraries\turtle\sequence.hpp" > - - diff --git a/build/vc80/turtle_test.vcproj b/build/vc80/turtle_test.vcproj index a429b86..8218b07 100644 --- a/build/vc80/turtle_test.vcproj +++ b/build/vc80/turtle_test.vcproj @@ -198,10 +198,6 @@ RelativePath="..\..\src\tests\turtle_test\error_test.cpp" > - - @@ -214,18 +210,22 @@ RelativePath="..\..\src\tests\turtle_test\invocation_test.cpp" > - - + + + + diff --git a/src/libraries/turtle/check.hpp b/src/libraries/turtle/check.hpp index 6315330..62b8b1c 100644 --- a/src/libraries/turtle/check.hpp +++ b/src/libraries/turtle/check.hpp @@ -12,7 +12,7 @@ #include "is_functor.hpp" #include "constraints.hpp" #include "operators.hpp" -#include "format.hpp" +#include "log.hpp" #include #include @@ -66,11 +66,11 @@ namespace detail friend std::ostream& operator<<( std::ostream& s, const check_base& c ) { - c.format( s ); + c.log( s ); return s; } private: - virtual void format( std::ostream& ) const = 0; + virtual void log( std::ostream& ) const = 0; }; template< typename Actual, typename Expected, typename Enable = void > @@ -87,9 +87,9 @@ namespace detail { return actual == expected_; } - virtual void format( std::ostream& s ) const + virtual void log( std::ostream& s ) const { - s << mock::format( expected_ ); + s << ::mock::format( expected_ ); } private: Expected expected_; @@ -110,9 +110,9 @@ namespace detail { return c_( actual ); } - virtual void format( std::ostream& s ) const + virtual void log( std::ostream& s ) const { - s << mock::format( c_ ); + s << ::mock::format( c_ ); } private: Constraint c_; @@ -136,9 +136,9 @@ namespace detail { return f_( actual ); } - virtual void format( std::ostream& s ) const + virtual void log( std::ostream& s ) const { - s << mock::format( f_ ); + s << ::mock::format( f_ ); } private: Functor f_; diff --git a/src/libraries/turtle/constraints.hpp b/src/libraries/turtle/constraints.hpp index 974130c..6a26e75 100644 --- a/src/libraries/turtle/constraints.hpp +++ b/src/libraries/turtle/constraints.hpp @@ -10,7 +10,7 @@ #define MOCK_CONSTRAINTS_HPP_INCLUDED #include "constraint.hpp" -#include "format.hpp" +#include "log.hpp" #include #include #include @@ -64,7 +64,7 @@ namespace mock } \ friend std::ostream& operator<<( std::ostream& s, const N& n ) \ { \ - return s << BOOST_STRINGIZE(N) << "( " << mock::format( n.expected_ ) << " )"; \ + return s << BOOST_STRINGIZE(N) << "( " << ::mock::format( n.expected_ ) << " )"; \ } \ Expected expected_; \ }; \ @@ -98,7 +98,7 @@ namespace detail } friend std::ostream& operator<<( std::ostream& os, const same& s ) { - return os << "same( " << mock::format( *s.expected_ ) << " )"; + return os << "same( " << ::mock::format( *s.expected_ ) << " )"; } const Expected* expected_; }; @@ -127,7 +127,7 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const assign& a ) { - return s << "assign( " << mock::format( a.expected_ ) << " )"; + return s << "assign( " << ::mock::format( a.expected_ ) << " )"; } Expected expected_; }; @@ -156,7 +156,7 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const retrieve& r ) { - return s << "retrieve( " << mock::format( *r.expected_ ) << " )"; + return s << "retrieve( " << ::mock::format( *r.expected_ ) << " )"; } Expected* expected_; }; @@ -173,7 +173,7 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const contain& n ) { - return s << "contain ( " << mock::format( n.expected_ ) << " )"; + return s << "contain ( " << ::mock::format( n.expected_ ) << " )"; } Expected expected_; }; diff --git a/src/libraries/turtle/function.hpp b/src/libraries/turtle/function.hpp index 11264d2..81d2637 100644 --- a/src/libraries/turtle/function.hpp +++ b/src/libraries/turtle/function.hpp @@ -13,7 +13,7 @@ #include "error.hpp" #include "expectation.hpp" #include "root.hpp" -#include "format.hpp" +#include "log.hpp" #include "args.hpp" #include #include @@ -205,7 +205,7 @@ namespace mock } #define MOCK_EXPECTATION_FORMAT(z, n, N) \ - << " " << mock::format( p##n ) << BOOST_PP_IF(BOOST_PP_EQUAL(N,n), " ", ",") + << " " << ::mock::format( p##n ) << BOOST_PP_IF(BOOST_PP_EQUAL(N,n), " ", ",") #define MOCK_EXPECTATION_CALL_CONTEXT(n) \ boost::unit_test::lazy_ostream::instance() \ << lazy_context( this ) \ diff --git a/src/libraries/turtle/is_formattable.hpp b/src/libraries/turtle/is_loggable.hpp similarity index 59% rename from src/libraries/turtle/is_formattable.hpp rename to src/libraries/turtle/is_loggable.hpp index af67f59..9fa7333 100644 --- a/src/libraries/turtle/is_formattable.hpp +++ b/src/libraries/turtle/is_loggable.hpp @@ -10,7 +10,6 @@ #define MOCK_IS_FORMATABLE_HPP_INCLUDED #include "yes_no_type.hpp" -#include "sink.hpp" #include #ifdef _MSC_VER @@ -22,25 +21,34 @@ namespace mock { namespace detail { -namespace formattable -{ - template< typename S > - detail::yes_type format( S&, detail::sink ); + struct sink + { + template< typename T > + sink( const T& ); + }; +} + template< typename S > + detail::no_type log( S&, detail::sink ); + +namespace detail +{ +namespace loggable +{ template< typename S, typename T > struct impl { static S* s; static T* t; // if an error is generated by the line below it means T has more than - // one conversion to other types which are formattable : the easiest - // solution would be to add a format function for T as well. - enum { value = sizeof( yes_type(), format( *s, *t ), yes_type() ) == sizeof( yes_type ) }; + // one conversion to other types which are loggable : the easiest + // solution would be to add a mock::log function for T as well. + enum { value = sizeof( yes_type(), ::mock::log( *s, *t ), yes_type() ) == sizeof( yes_type ) }; }; } template< typename S, typename T > - struct is_formattable - : boost::mpl::bool_< formattable::impl< S, T >::value > + struct is_loggable + : boost::mpl::bool_< loggable::impl< S, T >::value > {}; } } diff --git a/src/libraries/turtle/is_serializable.hpp b/src/libraries/turtle/is_serializable.hpp index 511ad7b..272245a 100644 --- a/src/libraries/turtle/is_serializable.hpp +++ b/src/libraries/turtle/is_serializable.hpp @@ -24,7 +24,7 @@ namespace detail namespace serializable { template< typename S, typename T > - yes_type operator<<( S&, const T& ); + no_type operator<<( S&, const T& ); template< typename S, typename T > struct impl diff --git a/src/libraries/turtle/format.hpp b/src/libraries/turtle/log.hpp similarity index 66% rename from src/libraries/turtle/format.hpp rename to src/libraries/turtle/log.hpp index c346712..d29a18b 100644 --- a/src/libraries/turtle/format.hpp +++ b/src/libraries/turtle/log.hpp @@ -10,7 +10,7 @@ #define MOCK_FORMAT_HPP_INCLUDED #include "is_serializable.hpp" -#include "is_formattable.hpp" +#include "is_loggable.hpp" #include #include #include @@ -28,17 +28,17 @@ namespace detail template< typename T > void serialize( std::ostream& s, const T& t, BOOST_DEDUCED_TYPENAME boost::enable_if< - BOOST_DEDUCED_TYPENAME detail::is_formattable< std::ostream, T > + BOOST_DEDUCED_TYPENAME detail::is_loggable< std::ostream, T > >::type* = 0 ) { - format( s, t ); + ::mock::log( s, t ); } template< typename T > void serialize( std::ostream& s, const T& t, BOOST_DEDUCED_TYPENAME boost::enable_if< boost::mpl::and_< boost::mpl::not_< - BOOST_DEDUCED_TYPENAME detail::is_formattable< std::ostream, T > + BOOST_DEDUCED_TYPENAME detail::is_loggable< std::ostream, T > >, BOOST_DEDUCED_TYPENAME detail::is_serializable< std::ostream, T > > @@ -50,7 +50,7 @@ namespace detail void serialize( std::ostream& s, const T&, BOOST_DEDUCED_TYPENAME boost::disable_if< boost::mpl::or_< - BOOST_DEDUCED_TYPENAME detail::is_formattable< std::ostream, T >, + BOOST_DEDUCED_TYPENAME detail::is_loggable< std::ostream, T >, BOOST_DEDUCED_TYPENAME detail::is_serializable< std::ostream, T > > >::type* = 0 ) @@ -82,7 +82,7 @@ namespace detail template< typename T > std::ostream& operator<<( std::ostream& s, protect< T > t ) { - format( s, t ); + ::mock::log( s, t ); return s; } @@ -93,36 +93,33 @@ namespace detail } template< typename T > - void format( std::ostream& s, protect< T > t, - BOOST_DEDUCED_TYPENAME boost::disable_if< - detail::is_container< T > - >::type* = 0 ) + void log( std::ostream& s, protect< T > t ) { detail::serialize( s, *t ); } - inline void format( std::ostream& s, protect< bool > b ) + inline void log( std::ostream& s, protect< bool > b ) { s << std::boolalpha << *b; } - inline void format( std::ostream& s, protect< std::string > str ) + inline void log( std::ostream& s, protect< std::string > str ) { s << '"' << *str << '"'; } - inline void format( std::ostream& s, protect< const char* > str ) + inline void log( std::ostream& s, protect< const char* > str ) { s << '"' << *str << '"'; } template< typename T1, typename T2 > - void format( std::ostream& s, protect< std::pair< T1, T2 > > p ) + void log( std::ostream& s, const std::pair< T1, T2 >& p ) { - s << '(' << mock::format( p->first ) - << ',' << mock::format( p->second ) << ')'; + s << '(' << ::mock::format( p.first ) + << ',' << ::mock::format( p.second ) << ')'; } template< typename T > - void format( std::ostream& s, protect< T* >, + void log( std::ostream& s, protect< T* >, BOOST_DEDUCED_TYPENAME boost::enable_if< boost::function_types::is_callable_builtin< T* > >::type* = 0 ) @@ -131,22 +128,22 @@ namespace detail } template< typename T > - void format( std::ostream& s, protect< T > c, + void log( std::ostream& s, T t, BOOST_DEDUCED_TYPENAME boost::enable_if< detail::is_container< T > >::type* = 0 ) { s << '('; // if an error is generated by the line below it means T is - // being mistaken for a container because it has a typedef - // const_iterator : the solution would be to add a format override - // for mock::protect< T >. - for( BOOST_DEDUCED_TYPENAME T::const_iterator it = c->begin(); - it != c->end(); ++it ) + // being mistaken for a container because it has an inner type + // const_iterator : the solution would be to add a mock::log + // override for T. + for( BOOST_DEDUCED_TYPENAME T::const_iterator it = t.begin(); + it != t.end(); ++it ) { - if( it != c->begin() ) + if( it != t.begin() ) s << ','; - s << mock::format( *it ); + s << ::mock::format( *it ); } s << ')'; } diff --git a/src/libraries/turtle/operators.hpp b/src/libraries/turtle/operators.hpp index 12ded04..3131c6d 100644 --- a/src/libraries/turtle/operators.hpp +++ b/src/libraries/turtle/operators.hpp @@ -10,7 +10,7 @@ #define MOCK_OPERATORS_HPP_INCLUDED #include "constraint.hpp" -#include "format.hpp" +#include "log.hpp" namespace mock { @@ -31,8 +31,8 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const and_& a ) { - return s << "( " << mock::format( a.c1_ ) - << " && " << mock::format( a.c2_ ) << " )"; + return s << "( " << ::mock::format( a.c1_ ) + << " && " << ::mock::format( a.c2_ ) << " )"; } private: Constraint1 c1_; @@ -54,8 +54,8 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const or_& o ) { - return s << "( " << mock::format( o.c1_ ) - << " || " << mock::format( o.c2_ )<< " )"; + return s << "( " << ::mock::format( o.c1_ ) + << " || " << ::mock::format( o.c2_ )<< " )"; } private: Constraint1 c1_; @@ -76,7 +76,7 @@ namespace detail } friend std::ostream& operator<<( std::ostream& s, const not_& n ) { - return s << "! " << mock::format( n.f_ ); + return s << "! " << ::mock::format( n.f_ ); } private: Constraint f_; diff --git a/src/libraries/turtle/sink.hpp b/src/libraries/turtle/sink.hpp deleted file mode 100644 index 0002caa..0000000 --- a/src/libraries/turtle/sink.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright Mathieu Champlon 2011 -// -// 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 MOCK_ANY_HPP_INCLUDED -#define MOCK_ANY_HPP_INCLUDED - -namespace mock -{ -namespace detail -{ - struct sink - { - template< typename T > - sink( const T& ); - }; -} -} - -#endif // #ifndef MOCK_ANY_HPP_INCLUDED diff --git a/src/libraries/turtle/yes_no_type.hpp b/src/libraries/turtle/yes_no_type.hpp index 9ec6063..ecfd518 100644 --- a/src/libraries/turtle/yes_no_type.hpp +++ b/src/libraries/turtle/yes_no_type.hpp @@ -23,7 +23,7 @@ namespace detail BOOST_STATIC_ASSERT( sizeof( yes_type ) != sizeof( no_type ) ); template< typename T > void operator,( yes_type, const T& ); - no_type operator,( yes_type, yes_type ); + no_type operator,( yes_type, no_type ); no_type operator,( no_type, yes_type ); } } diff --git a/src/tests/turtle_test/is_formattable_test.cpp b/src/tests/turtle_test/is_formattable_test.cpp deleted file mode 100644 index 724da75..0000000 --- a/src/tests/turtle_test/is_formattable_test.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright Mathieu Champlon 2011 -// -// 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) -// - -#include - -#include -#define BOOST_LIB_NAME boost_unit_test_framework -#include - -BOOST_MPL_ASSERT_NOT(( mock::detail::is_formattable< std::ostream, int > )); - -namespace -{ - struct non_formattable {}; -} - -BOOST_MPL_ASSERT_NOT(( mock::detail::is_formattable< std::ostream, non_formattable > )); - -namespace -{ - struct formattable {}; - - void format( std::ostream&, const formattable& ); -} - -BOOST_MPL_ASSERT(( mock::detail::is_formattable< std::ostream, formattable > )); - -namespace -{ - struct derived_from_formattable : formattable - {}; -} - -BOOST_MPL_ASSERT(( mock::detail::is_formattable< std::ostream, derived_from_formattable > )); - -namespace -{ - struct convertible_to_formattable - { - operator formattable() const; - }; -} - -BOOST_MPL_ASSERT(( mock::detail::is_formattable< std::ostream, convertible_to_formattable > )); diff --git a/src/tests/turtle_test/is_loggable_test.cpp b/src/tests/turtle_test/is_loggable_test.cpp new file mode 100644 index 0000000..f894a99 --- /dev/null +++ b/src/tests/turtle_test/is_loggable_test.cpp @@ -0,0 +1,54 @@ +// +// Copyright Mathieu Champlon 2011 +// +// 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) +// + +#include + +#include +#define BOOST_LIB_NAME boost_unit_test_framework +#include + +BOOST_MPL_ASSERT_NOT(( mock::detail::is_loggable< std::ostream, int > )); + +namespace +{ + struct non_loggable {}; + + void log( std::ostream&, const non_loggable& ); +} + +BOOST_MPL_ASSERT_NOT(( mock::detail::is_loggable< std::ostream, non_loggable > )); + +namespace +{ + struct loggable {}; +} + +namespace mock +{ + void log( std::ostream&, const loggable& ); +} + +BOOST_MPL_ASSERT(( mock::detail::is_loggable< std::ostream, loggable > )); + +namespace +{ + struct derived_from_loggable : loggable + {}; +} + +BOOST_MPL_ASSERT(( mock::detail::is_loggable< std::ostream, derived_from_loggable > )); + +namespace +{ + struct convertible_to_loggable + { + operator loggable() const; + }; +} + +BOOST_MPL_ASSERT(( mock::detail::is_loggable< std::ostream, convertible_to_loggable > )); diff --git a/src/tests/turtle_test/format_test.cpp b/src/tests/turtle_test/log_test.cpp similarity index 57% rename from src/tests/turtle_test/format_test.cpp rename to src/tests/turtle_test/log_test.cpp index 176b2a8..fd2269f 100644 --- a/src/tests/turtle_test/format_test.cpp +++ b/src/tests/turtle_test/log_test.cpp @@ -6,7 +6,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // -#include +#include #include #include #include @@ -24,7 +24,7 @@ namespace std::string to_string( T t ) { std::stringstream s; - s << mock::format( t ); + s << ::mock::format( t ); return s.str(); } } @@ -33,6 +33,15 @@ namespace { struct non_serializable {}; + + void log( std::ostream&, const non_serializable& ) + { + BOOST_FAIL( "should not be called" ); + } + void log( std::ostream&, mock::protect< non_serializable > ) + { + BOOST_FAIL( "should not be called" ); + } } BOOST_AUTO_TEST_CASE( non_serializable_type_yields_an_interrogation_mark_when_serialized ) @@ -58,54 +67,57 @@ BOOST_AUTO_TEST_CASE( serializable_type_yields_its_value_when_serialized ) namespace { - struct formattable {}; + struct loggable {}; - std::ostream& operator<<( std::ostream& s, const formattable& ) + std::ostream& operator<<( std::ostream& s, const loggable& ) { BOOST_FAIL( "should not be called" ); return s; } } -BOOST_AUTO_TEST_CASE( format_overrides_standard_stream_serialization_even_if_defined_after_being_used ) +BOOST_AUTO_TEST_CASE( mock_log_overrides_standard_stream_serialization_even_if_defined_after_being_used ) { - BOOST_CHECK_EQUAL( "formattable", to_string( formattable() ) ); + BOOST_CHECK_EQUAL( "loggable", to_string( loggable() ) ); } -namespace +namespace mock { - void format( std::ostream& s, const formattable& ) + void log( std::ostream& s, const loggable& ) { - s << "formattable"; + s << "loggable"; } } namespace { - struct protected_formattable {}; + struct protected_loggable {}; - std::ostream& operator<<( std::ostream& s, const protected_formattable& ) + std::ostream& operator<<( std::ostream& s, const protected_loggable& ) { BOOST_FAIL( "should not be called" ); return s; } +} - void format( std::ostream&, const protected_formattable& ) +namespace mock +{ + void log( std::ostream&, const protected_loggable& ) { BOOST_FAIL( "should not be called" ); } } -BOOST_AUTO_TEST_CASE( protected_format_overrides_standard_stream_serialization_and_format_even_if_defined_after_being_used ) +BOOST_AUTO_TEST_CASE( protected_mock_log_overrides_standard_stream_serialization_and_mock_log_even_if_defined_after_being_used ) { - BOOST_CHECK_EQUAL( "protected_formattable", to_string( protected_formattable() ) ); + BOOST_CHECK_EQUAL( "protected_loggable", to_string( protected_loggable() ) ); } -namespace +namespace mock { - void format( std::ostream& s, mock::protect< protected_formattable > ) + void log( std::ostream& s, mock::protect< protected_loggable > ) { - s << "protected_formattable"; + s << "protected_loggable"; } } @@ -197,6 +209,18 @@ BOOST_AUTO_TEST_CASE( boost_assign_map_list_of_are_serialized ) BOOST_CHECK_EQUAL( "((12,\"12\"),(42,\"42\"))", to_string( boost::assign::map_list_of( 12, "12" )( 42, "42" ) ) ); } +namespace +{ + void callable_builtin() + {} +} + +BOOST_AUTO_TEST_CASE( callable_builtin_cannot_be_serialized ) +{ + BOOST_CHECK_EQUAL( "?", to_string( &callable_builtin ) ); + BOOST_CHECK_EQUAL( "?", to_string( callable_builtin ) ); +} + namespace { struct false_positive_container @@ -204,14 +228,75 @@ namespace typedef int const_iterator; }; BOOST_MPL_ASSERT(( mock::detail::is_container< false_positive_container > )); +} - void format( std::ostream& s, mock::protect< false_positive_container > ) +namespace mock +{ + void log( std::ostream& s, false_positive_container ) { s << "false_positive_container"; } } -BOOST_AUTO_TEST_CASE( false_positive_container_serialization_can_still_be_overriden ) +BOOST_AUTO_TEST_CASE( false_positive_container_serialization_can_be_overriden ) { BOOST_CHECK_EQUAL( "false_positive_container", to_string( false_positive_container() ) ); } + +namespace +{ + template< typename T > + struct template_type + {}; +} + +namespace mock +{ + template< typename T > + void log( std::ostream& s, template_type< T > ) + { + s << "template_type"; + } +} + +BOOST_AUTO_TEST_CASE( template_type_serialization_can_be_overriden ) +{ + BOOST_CHECK_EQUAL( "template_type", to_string( template_type< int >() ) ); +} + +namespace mock +{ + void log( std::ostream& s, const std::vector< float >& ) + { + s << "vector< float >"; + } +} + +BOOST_AUTO_TEST_CASE( vector_of_floats_serialization_can_be_overriden ) +{ + BOOST_CHECK_EQUAL( "vector< float >", to_string( std::vector< float >() ) ); +} + +namespace +{ + struct convertible_to_many + { + operator bool() const; + operator std::string() const; + operator const char*() const; + + operator std::pair< int, int >() const; + template< typename T1, typename T2 > operator std::pair< T1, T2 >() const; + + typedef void (*pf)(); + operator pf() const; + + operator std::set< int >() const; + template< typename T > operator std::set< T >() const; + }; +} + +BOOST_AUTO_TEST_CASE( build_in_log_customizations_do_not_yield_ambiguous_errors ) +{ + BOOST_CHECK_EQUAL( "?", to_string( convertible_to_many() ) ); +}