Skip to content

Ambiguous template errors when compiling catch2 tests using GCC 16.1.0 and C++26 #3095

@t-b

Description

@t-b

Describe the bug

When compiling with GCC 16.1.0 and C++26 (still experimental) I get the following compilation error:

$LANG=C cmake --build build --parallel 1
[  9%] Built target Catch2
[  9%] Built target Catch2WithMain
[  9%] Built target AssertionsFastPath
[  9%] Built target AssertionsSlowPath
[ 40%] Built target Catch2SurrogateTarget
[ 40%] Building CXX object tests/CMakeFiles/SelfTest.dir/SelfTest/UsageTests/ToStringOptional.tests.cpp.o
In file included from /home/thomas/devel/Catch2/src/catch2/../catch2/internal/catch_decomposer.hpp:11,
                 from /home/thomas/devel/Catch2/src/catch2/../catch2/internal/catch_assertion_handler.hpp:12,
                 from /home/thomas/devel/Catch2/src/catch2/../catch2/internal/catch_test_macro_impl.hpp:12,
                 from /home/thomas/devel/Catch2/src/catch2/../catch2/catch_test_macros.hpp:11,
                 from /home/thomas/devel/Catch2/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp:10:
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp: In instantiation of 'std::string Catch::Detail::stringify(const T&) [with T = std::optional<int>; std::string = std::__cxx11::basic_string<char>]':
/home/thomas/devel/Catch2/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp:16:5:   required from here
   16 |     REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
      |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:147:75: error: ambiguous template instantiation for 'struct Catch::StringMaker<std::optional<int>, void>'
  146 |                 return ::Catch::StringMaker<
      |                        ~~~~~~~~~~~~~~~~~~~~~                               
  147 |                     std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:391:12: note: candidates are: 'template<class T> struct Catch::StringMaker<std::optional<_Tp> > [with T = int]'
  391 |     struct StringMaker<std::optional<T> > {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:519:12: note:                 'template<class R> struct Catch::StringMaker<R, typename std::enable_if<(Catch::is_range<T>::value && (! IsStreamInsertable_v<R, void>)), void>::type> [with R = std::optional<int>]'
  519 |     struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable_v<R>>> {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:147:75: error: incomplete type 'Catch::StringMaker<std::optional<int>, void>' used in nested name specifier
  146 |                 return ::Catch::StringMaker<
      |                        ~~~~~~~~~~~~~~~~~~~~~                               
  147 |                     std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp: In instantiation of 'std::string Catch::Detail::stringify(const T&) [with T = std::optional<std::__cxx11::basic_string<char> >; std::string = std::__cxx11::basic_string<char>]':
/home/thomas/devel/Catch2/tests/SelfTest/UsageTests/ToStringOptional.tests.cpp:22:5:   required from here
   22 |     REQUIRE( "{ }" == ::Catch::Detail::stringify( type{} ) );
      |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:147:75: error: ambiguous template instantiation for 'struct Catch::StringMaker<std::optional<std::__cxx11::basic_string<char> >, void>'
  146 |                 return ::Catch::StringMaker<
      |                        ~~~~~~~~~~~~~~~~~~~~~                               
  147 |                     std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:391:12: note: candidates are: 'template<class T> struct Catch::StringMaker<std::optional<_Tp> > [with T = std::__cxx11::basic_string<char>]'
  391 |     struct StringMaker<std::optional<T> > {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:519:12: note:                 'template<class R> struct Catch::StringMaker<R, typename std::enable_if<(Catch::is_range<T>::value && (! IsStreamInsertable_v<R, void>)), void>::type> [with R = std::optional<std::__cxx11::basic_string<char> >]'
  519 |     struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable_v<R>>> {
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/thomas/devel/Catch2/src/catch2/../catch2/catch_tostring.hpp:147:75: error: incomplete type 'Catch::StringMaker<std::optional<std::__cxx11::basic_string<char> >, void>' used in nested name specifier
  146 |                 return ::Catch::StringMaker<
      |                        ~~~~~~~~~~~~~~~~~~~~~                               
  147 |                     std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
gmake[2]: *** [tests/CMakeFiles/SelfTest.dir/build.make:751: tests/CMakeFiles/SelfTest.dir/SelfTest/UsageTests/ToStringOptional.tests.cpp.o] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:1427: tests/CMakeFiles/SelfTest.dir/all] Error 2
gmake: *** [Makefile:166: all] Error 2

I've used a locally compiled gcc (which works on other projects) and patched the presets a la

diff --git a/CMakePresets.json b/CMakePresets.json
index ffc6e240..639c1a61 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -33,7 +33,9 @@
             "description": "Enables development build with examples and ALL tests",
             "cacheVariables": {
                 "CATCH_ENABLE_CONFIGURE_TESTS": "ON",
-                "CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON"
+                "CATCH_ENABLE_CMAKE_HELPER_TESTS": "ON",
+                "CMAKE_CXX_COMPILER": "/rest/inst/gcc-16.1.0/usr/local/bin/g++",
+                "CMAKE_CXX_STANDARD": "26"
             }
         }
     ]   

And it also fails on godbolt, see https://godbolt.org/z/sahn8f9n7.

Platform information:

  • OS: debian trixie
  • Compiler+version: g++ (GCC) 16.1.0
  • Catch version:300c5d3e (Fix Wconversion warning in catch_reporter_helpers.cpp, 2026-05-05)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions