vendredi 17 juin 2022

clang says C++ code is ambiguous, gcc accepts it, which one is right?

I'm trying to port some code written for GCC (8.2) to be compilable by clang:

#include <tuple>

struct Q{};

using TUP = std::tuple<Q>;


template<typename Fn>
inline
void feh(Fn&, const std::tuple<>*)
{}

template<typename Fn, typename H>
inline
void feh(Fn& fn, const std::tuple<H>*)
{
    fn(H{});
}

template<typename  Fn, typename H, typename... R>
inline
void feh(Fn& fn, const std::tuple<H, R...>*)
{
    fn(H{});
    using Rest = const std::tuple<R...>*;
    feh<Fn, R...>(fn, static_cast<Rest>(nullptr));
}

template<typename Tuple, typename Fn>
inline
void fe(Fn& fn, const Tuple  *  tpl =  nullptr)
{
    feh(fn, tpl);
}

int main()
{
    auto r = [] (Q const&) {};
    TUP tup;
    fe<TUP>(r, &tup);
}

GCC 8.2 (and 12.1) compiles the code just fine. However, clang 11.0.0 (and 14.0.0) complains that the call from fe to feh is ambiguous between void feh(Fn& fn, const std::tuple<H>*) [with Fn = (lambda at <source>:38:14), H = Q] and void feh(Fn& fn, const std::tuple<H, R...>*) [with Fn = (lambda at <source>:38:14), H = Q, R = <>].

https://godbolt.org/z/5E9M6a5c6

Which compiler is right?

How can I write this code so both compilers accept it?


Edit after answers have been posted:

Both if constexpr and fold expressions would work in C++17, but this is a library header included by many projects, and not all of them are compiled with C++17. I need a solution which works in C++11.

Aucun commentaire:

Enregistrer un commentaire