mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 07:16:10 +01:00
Fix ambiguity in stringification
Happening when using clang and templated operators, clang cannot decide between the operator provided by ReusableStringStream and the one provided by the value value as both are templates. This is easily solved by calling the operator<< through the member syntax. Fixes #1285
This commit is contained in:
parent
021fcee636
commit
7be8a41adf
@ -105,7 +105,9 @@ namespace Catch {
|
|||||||
typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
|
typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
|
||||||
convert(const Fake& value) {
|
convert(const Fake& value) {
|
||||||
ReusableStringStream rss;
|
ReusableStringStream rss;
|
||||||
rss << value;
|
// NB: call using the function-like syntax to avoid ambiguity with
|
||||||
|
// user-defined templated operator<< under clang.
|
||||||
|
rss.operator<<(value);
|
||||||
return rss.str();
|
return rss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,6 +1065,9 @@ ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(item)
|
|||||||
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )"
|
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )"
|
||||||
==
|
==
|
||||||
"operator<<( has_operator )"
|
"operator<<( has_operator )"
|
||||||
|
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" for: "operator<<( has_template_operator )"
|
||||||
|
==
|
||||||
|
"operator<<( has_template_operator )"
|
||||||
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" for: "{ StringMaker<has_maker> }"
|
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" for: "{ StringMaker<has_maker> }"
|
||||||
==
|
==
|
||||||
"{ StringMaker<has_maker> }"
|
"{ StringMaker<has_maker> }"
|
||||||
|
@ -1084,6 +1084,6 @@ due to unexpected exception with message:
|
|||||||
Why would you throw a std::string?
|
Why would you throw a std::string?
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 207 | 154 passed | 49 failed | 4 failed as expected
|
test cases: 208 | 155 passed | 49 failed | 4 failed as expected
|
||||||
assertions: 1064 | 936 passed | 107 failed | 21 failed as expected
|
assertions: 1065 | 937 passed | 107 failed | 21 failed as expected
|
||||||
|
|
||||||
|
@ -8407,6 +8407,20 @@ with expansion:
|
|||||||
==
|
==
|
||||||
"operator<<( has_operator )"
|
"operator<<( has_operator )"
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
stringify( has_template_operator )
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
ToStringWhich.tests.cpp:<line number>
|
||||||
|
...............................................................................
|
||||||
|
|
||||||
|
ToStringWhich.tests.cpp:<line number>:
|
||||||
|
PASSED:
|
||||||
|
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" )
|
||||||
|
with expansion:
|
||||||
|
"operator<<( has_template_operator )"
|
||||||
|
==
|
||||||
|
"operator<<( has_template_operator )"
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
stringify( vectors<has_maker> )
|
stringify( vectors<has_maker> )
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@ -8978,6 +8992,6 @@ Misc.tests.cpp:<line number>:
|
|||||||
PASSED:
|
PASSED:
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
test cases: 207 | 141 passed | 62 failed | 4 failed as expected
|
test cases: 208 | 142 passed | 62 failed | 4 failed as expected
|
||||||
assertions: 1078 | 936 passed | 121 failed | 21 failed as expected
|
assertions: 1079 | 937 passed | 121 failed | 21 failed as expected
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuitesloose text artifact
|
<testsuitesloose text artifact
|
||||||
>
|
>
|
||||||
<testsuite name="<exe-name>" errors="17" failures="105" tests="1079" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
<testsuite name="<exe-name>" errors="17" failures="105" tests="1080" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
|
||||||
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
|
||||||
@ -838,6 +838,7 @@ Tricky.tests.cpp:<line number>
|
|||||||
<testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
|
||||||
|
<testcase classname="<exe-name>.global" name="stringify( has_template_operator )" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker> )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker> )" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( vectors<has_maker_and_operator> )" time="{duration}"/>
|
||||||
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}"/>
|
<testcase classname="<exe-name>.global" name="stringify( vectors<has_operator> )" time="{duration}"/>
|
||||||
|
@ -9366,6 +9366,19 @@ loose text artifact
|
|||||||
</Expression>
|
</Expression>
|
||||||
<OverallResult success="true"/>
|
<OverallResult success="true"/>
|
||||||
</TestCase>
|
</TestCase>
|
||||||
|
<TestCase name="stringify( has_template_operator )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
||||||
|
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
||||||
|
<Original>
|
||||||
|
::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )"
|
||||||
|
</Original>
|
||||||
|
<Expanded>
|
||||||
|
"operator<<( has_template_operator )"
|
||||||
|
==
|
||||||
|
"operator<<( has_template_operator )"
|
||||||
|
</Expanded>
|
||||||
|
</Expression>
|
||||||
|
<OverallResult success="true"/>
|
||||||
|
</TestCase>
|
||||||
<TestCase name="stringify( vectors<has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
<TestCase name="stringify( vectors<has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
||||||
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
|
||||||
<Original>
|
<Original>
|
||||||
@ -9923,7 +9936,7 @@ loose text artifact
|
|||||||
</Section>
|
</Section>
|
||||||
<OverallResult success="true"/>
|
<OverallResult success="true"/>
|
||||||
</TestCase>
|
</TestCase>
|
||||||
<OverallResults successes="936" failures="122" expectedFailures="21"/>
|
<OverallResults successes="937" failures="122" expectedFailures="21"/>
|
||||||
</Group>
|
</Group>
|
||||||
<OverallResults successes="936" failures="121" expectedFailures="21"/>
|
<OverallResults successes="937" failures="121" expectedFailures="21"/>
|
||||||
</Catch>
|
</Catch>
|
||||||
|
@ -20,6 +20,7 @@ struct has_operator { };
|
|||||||
struct has_maker {};
|
struct has_maker {};
|
||||||
struct has_maker_and_operator {};
|
struct has_maker_and_operator {};
|
||||||
struct has_neither {};
|
struct has_neither {};
|
||||||
|
struct has_template_operator {};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const has_operator&) {
|
std::ostream& operator<<(std::ostream& os, const has_operator&) {
|
||||||
os << "operator<<( has_operator )";
|
os << "operator<<( has_operator )";
|
||||||
@ -31,6 +32,12 @@ std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename StreamT>
|
||||||
|
StreamT& operator<<(StreamT& os, const has_template_operator&) {
|
||||||
|
os << "operator<<( has_template_operator )";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
template<>
|
template<>
|
||||||
struct StringMaker<has_maker> {
|
struct StringMaker<has_maker> {
|
||||||
@ -69,6 +76,12 @@ TEST_CASE("stringify( has_neither )", "[toString]") {
|
|||||||
REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
|
REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call the templated operator
|
||||||
|
TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
|
||||||
|
has_template_operator item;
|
||||||
|
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Vectors...
|
// Vectors...
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user