Skip to content

Commit 7be8a41

Browse files
jnitard-jumphorenmar
authored andcommitted
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
1 parent 021fcee commit 7be8a41

File tree

7 files changed

+54
-8
lines changed

7 files changed

+54
-8
lines changed

include/internal/catch_tostring.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ namespace Catch {
105105
typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
106106
convert(const Fake& value) {
107107
ReusableStringStream rss;
108-
rss << value;
108+
// NB: call using the function-like syntax to avoid ambiguity with
109+
// user-defined templated operator<< under clang.
110+
rss.operator<<(value);
109111
return rss.str();
110112
}
111113

projects/SelfTest/Baselines/compact.sw.approved.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,9 @@ ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify(item)
10651065
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_operator )" for: "operator<<( has_operator )"
10661066
==
10671067
"operator<<( has_operator )"
1068+
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" for: "operator<<( has_template_operator )"
1069+
==
1070+
"operator<<( has_template_operator )"
10681071
ToStringWhich.tests.cpp:<line number>: passed: ::Catch::Detail::stringify( v ) == "{ StringMaker<has_maker> }" for: "{ StringMaker<has_maker> }"
10691072
==
10701073
"{ StringMaker<has_maker> }"

projects/SelfTest/Baselines/console.std.approved.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,6 @@ due to unexpected exception with message:
10841084
Why would you throw a std::string?
10851085

10861086
===============================================================================
1087-
test cases: 207 | 154 passed | 49 failed | 4 failed as expected
1088-
assertions: 1064 | 936 passed | 107 failed | 21 failed as expected
1087+
test cases: 208 | 155 passed | 49 failed | 4 failed as expected
1088+
assertions: 1065 | 937 passed | 107 failed | 21 failed as expected
10891089

projects/SelfTest/Baselines/console.sw.approved.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8407,6 +8407,20 @@ with expansion:
84078407
==
84088408
"operator<<( has_operator )"
84098409

8410+
-------------------------------------------------------------------------------
8411+
stringify( has_template_operator )
8412+
-------------------------------------------------------------------------------
8413+
ToStringWhich.tests.cpp:<line number>
8414+
...............................................................................
8415+
8416+
ToStringWhich.tests.cpp:<line number>:
8417+
PASSED:
8418+
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" )
8419+
with expansion:
8420+
"operator<<( has_template_operator )"
8421+
==
8422+
"operator<<( has_template_operator )"
8423+
84108424
-------------------------------------------------------------------------------
84118425
stringify( vectors<has_maker> )
84128426
-------------------------------------------------------------------------------
@@ -8978,6 +8992,6 @@ Misc.tests.cpp:<line number>:
89788992
PASSED:
89798993

89808994
===============================================================================
8981-
test cases: 207 | 141 passed | 62 failed | 4 failed as expected
8982-
assertions: 1078 | 936 passed | 121 failed | 21 failed as expected
8995+
test cases: 208 | 142 passed | 62 failed | 4 failed as expected
8996+
assertions: 1079 | 937 passed | 121 failed | 21 failed as expected
89838997

projects/SelfTest/Baselines/junit.sw.approved.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<testsuitesloose text artifact
33
>
4-
<testsuite name="<exe-name>" errors="17" failures="105" tests="1079" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
4+
<testsuite name="<exe-name>" errors="17" failures="105" tests="1080" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
55
<testcase classname="<exe-name>.global" name="# A test name that starts with a #" time="{duration}"/>
66
<testcase classname="<exe-name>.global" name="#1005: Comparing pointer to int and long (NULL can be either on various systems)" time="{duration}"/>
77
<testcase classname="<exe-name>.global" name="#1027" time="{duration}"/>
@@ -838,6 +838,7 @@ Tricky.tests.cpp:<line number>
838838
<testcase classname="<exe-name>.global" name="stringify( has_maker_and_operator )" time="{duration}"/>
839839
<testcase classname="<exe-name>.global" name="stringify( has_neither )" time="{duration}"/>
840840
<testcase classname="<exe-name>.global" name="stringify( has_operator )" time="{duration}"/>
841+
<testcase classname="<exe-name>.global" name="stringify( has_template_operator )" time="{duration}"/>
841842
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker> )" time="{duration}"/>
842843
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_maker_and_operator> )" time="{duration}"/>
843844
<testcase classname="<exe-name>.global" name="stringify( vectors&lt;has_operator> )" time="{duration}"/>

projects/SelfTest/Baselines/xml.sw.approved.txt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9366,6 +9366,19 @@ loose text artifact
93669366
</Expression>
93679367
<OverallResult success="true"/>
93689368
</TestCase>
9369+
<TestCase name="stringify( has_template_operator )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
9370+
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
9371+
<Original>
9372+
::Catch::Detail::stringify( item ) == "operator&lt;&lt;( has_template_operator )"
9373+
</Original>
9374+
<Expanded>
9375+
"operator&lt;&lt;( has_template_operator )"
9376+
==
9377+
"operator&lt;&lt;( has_template_operator )"
9378+
</Expanded>
9379+
</Expression>
9380+
<OverallResult success="true"/>
9381+
</TestCase>
93699382
<TestCase name="stringify( vectors&lt;has_maker> )" tags="[toString]" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
93709383
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/ToStringWhich.tests.cpp" >
93719384
<Original>
@@ -9923,7 +9936,7 @@ loose text artifact
99239936
</Section>
99249937
<OverallResult success="true"/>
99259938
</TestCase>
9926-
<OverallResults successes="936" failures="122" expectedFailures="21"/>
9939+
<OverallResults successes="937" failures="122" expectedFailures="21"/>
99279940
</Group>
9928-
<OverallResults successes="936" failures="121" expectedFailures="21"/>
9941+
<OverallResults successes="937" failures="121" expectedFailures="21"/>
99299942
</Catch>

projects/SelfTest/UsageTests/ToStringWhich.tests.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct has_operator { };
2020
struct has_maker {};
2121
struct has_maker_and_operator {};
2222
struct has_neither {};
23+
struct has_template_operator {};
2324

2425
std::ostream& operator<<(std::ostream& os, const has_operator&) {
2526
os << "operator<<( has_operator )";
@@ -31,6 +32,12 @@ std::ostream& operator<<(std::ostream& os, const has_maker_and_operator&) {
3132
return os;
3233
}
3334

35+
template <typename StreamT>
36+
StreamT& operator<<(StreamT& os, const has_template_operator&) {
37+
os << "operator<<( has_template_operator )";
38+
return os;
39+
}
40+
3441
namespace Catch {
3542
template<>
3643
struct StringMaker<has_maker> {
@@ -69,6 +76,12 @@ TEST_CASE("stringify( has_neither )", "[toString]") {
6976
REQUIRE( ::Catch::Detail::stringify(item) == "{ !!! }" );
7077
}
7178

79+
// Call the templated operator
80+
TEST_CASE( "stringify( has_template_operator )", "[toString]" ) {
81+
has_template_operator item;
82+
REQUIRE( ::Catch::Detail::stringify( item ) == "operator<<( has_template_operator )" );
83+
}
84+
7285

7386
// Vectors...
7487

0 commit comments

Comments
 (0)