[Bug c++/102670] New: Erroneous "missing template arguments" message for wrapper of ADL function template
friedkeenan at protonmail dot com
gcc-bugzilla@gcc.gnu.org
Sat Oct 9 18:51:32 GMT 2021
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102670
Bug ID: 102670
Summary: Erroneous "missing template arguments" message for
wrapper of ADL function template
Product: gcc
Version: 12.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: friedkeenan at protonmail dot com
Target Milestone: ---
With the following code, GCC outputs an erroneous error message of "missing
template arguments":
#include <utility>
namespace ns {
struct S { };
template<int I>
constexpr int adl(const S &) {
return I;
}
}
namespace redirect {
template<typename T, int I>
concept can_call_adl = requires(T &&t) {
adl<I>(std::forward<T>(t));
};
template<int I>
struct adl_fn {
template<can_call_adl<I> T>
constexpr decltype(auto) operator ()(T &&t) const {
return adl<I>(std::forward<T>(t));
}
};
namespace {
template<int I>
constexpr inline adl_fn<I> adl{};
}
}
static_assert(redirect::can_call_adl<ns::S, 3>);
int main() {
// return adl<3>(ns::S{});
return redirect::adl<3>(ns::S{});
}
Godbolt link: https://godbolt.org/z/or5n8EM6q
As you can see, even though ns::S satisfies the redirect::can_call_adl concept,
when the templated call operator is instantiated, it thinks the code is
invalid. If you remove the indirection, no error message is presented and
everything works as expected. Additionally, Clang handles this code just fine.
If you however use the following code, everything works fine:
#include <utility>
namespace ns {
struct S { };
template<int I>
constexpr int adl(const S &) {
return I;
}
}
namespace redirect {
namespace _adl {
/* Poison pill. */
template<int I>
void adl() = delete;
template<typename T, int I>
concept can_call_adl = requires(T &&t) {
adl<I>(std::forward<T>(t));
};
template<int I>
struct adl_fn {
template<can_call_adl<I> T>
constexpr decltype(auto) operator ()(T &&t) const {
return adl<I>(std::forward<T>(t));
}
};
}
namespace {
template<int I>
constexpr inline _adl::adl_fn<I> adl{};
}
}
static_assert(redirect::_adl::can_call_adl<ns::S, 3>);
int main() {
// return adl<3>(ns::S{});
return redirect::adl<3>(ns::S{});
}
Godbolt link: https://godbolt.org/z/jocaKrjbW
This sort of functionality is desirable for making a wrapper that handles both
ADL-discovered `get` functions and `get` member functions (as structured
binding allows both), similar to the std::ranges::begin etc. wrappers.
More information about the Gcc-bugs
mailing list