Pardon the confusing title.
I have this code, which is accepted by GCC, Clang, and MSVC:
#include <type_traits>
template <typename T>
struct Reader
{
friend auto adl(Reader<T>);
};
template <typename T, typename U>
struct Writer
{
friend auto adl(Reader<T>) {return U{};}
};
struct A
{
struct Tag {};
auto helper() -> decltype(void(Writer<Tag,decltype(this)>{})) {}
using Self = std::remove_pointer_t<decltype(adl(Reader<Tag>{}))>;
};
It uses stateful metaprogramming to write a type, and then read it back.
Notice the weird use of Writer. I thought I could simplify it to:
auto helper() -> Writer<Tag,decltype(this)> {return {};}
But then it stops working (on all three compilers), due to Writer being instantiated after the read happens. run on gcc.godbolt.org
But if I then move using Self = ... to a static function body below helper, it starts working again. Meaning Writer is now instantiated along with the body of helper, not with its declaration.
After experimenting with different return types, it seems that Writer is instantiated early whenever it's used as a type of an expression. Here's another example: auto helper() -> std::enable_if_t<(Writer<Tag,decltype(this)>{}, true), void> {}
What causes this difference? Since the three compilers agree on this, it's not a fluke of stateful templates, right?