I have an issue which is quite similar to this one.
In short, I have a magic method, which is noexcept if another method is noexcept.
The weird thing is that this "another method" has two overloads, and the compiler chooses the second overload to determine magic noexcept-ness.
However, when magic is called later on, the first overload is called, but the noexcept-ness of magic remains the same!
Here is the wandbox link
From what I understand:
noexcept(magic(dummy2{}))callsnoexcept(noexcept(adl_caller(...))which falls back toadl_caller(..., priority_tag<0>) noexceptsinceuser_method(dummy2)is not known by the compiler at this point.
Fair enough, however, how is user_method(dummy2) called 3 lines above?
Is this intended by the Standard?
Sorry if I'm not clear enough.
#include <iostream>
template <unsigned N> struct priority_tag : priority_tag<N - 1> {};
template <> struct priority_tag<0> {};
template <typename T>
auto adl_caller(T t, priority_tag<1>) noexcept(noexcept(user_method(t)))
-> decltype(user_method(t)) {
std::cout << "first adl_caller overload" << std::endl;
user_method(t);
}
// tricky noexcept ...
template <typename T> void adl_caller(T, priority_tag<0>) noexcept {
std::cout << "second adl_caller overload" << std::endl;
}
template <typename T>
void magic(T t) noexcept(noexcept(adl_caller(t, priority_tag<1>{}))) {
adl_caller(t, priority_tag<1>{});
}
struct dummy {};
struct dummy2 {};
// un-commenting this line makes the above call to cout print '0'
// void user_method(dummy2);
void user_method(dummy)
{
// user_method(dummy2) is declared after this point
// this line prints '1', since magic falls back to the second adl_caller overload
std::cout << "noexcept?: " << noexcept(magic(dummy2{})) << std::endl;
std::cout << "dummy method called" << std::endl;
// however, the first adl_caller overload is called here ...
magic(dummy2{});
}
void user_method(dummy2)
{
std::cout << "dummy2 method called" << std::endl;
}
int main()
{
magic(dummy{});
}