The one case we can handle is when source local name lookup results in a variable.
If it isn't templated, func<targs>(obj) can't be valid, so the only option is the member call.
See https://cpp2.godbolt.org/z/T6sdezYKh:
t: @struct type = {
f: <T> (this) = { }
g: <T> (this) = { }
}
main: () = {
t().f<int>(); // OK.
g := 0;
// error: 'g' does not name a template but is followed by template arguments
t().g<int>();
_ = g;
}
auto main() -> int{
CPP2_UFCS_TEMPLATE(f<int>)(t());// OK.
auto g {0};
CPP2_UFCS_TEMPLATE(g<int>)(t());// S
static_cast<void>(std::move(g));
}
main.cpp2:10:22: error: 'g' does not name a template but is followed by template arguments
10 | CPP2_UFCS_TEMPLATE(g<int>)(t());
| ^~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:855:84: note: expanded from macro 'CPP2_UFCS_TEMPLATE'
855 | #define CPP2_UFCS_TEMPLATE(...) CPP2_UFCS_(&,(),template,__VA_ARGS__)
| ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:845:51: note: expanded from macro 'CPP2_UFCS_'
845 | noexcept(CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,__VA_ARGS__)) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) \
| ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:803:90: note: expanded from macro 'CPP2_UFCS_IS_NOTHROW_ARG'
803 | #define CPP2_UFCS_IS_NOTHROW_ARG(QUALID,TEMPKW,...) CPP2_UFCS_IS_NOTHROW(QUALID,TEMPKW,__VA_ARGS__)
| ^~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:801:60: note: expanded from macro 'CPP2_UFCS_IS_NOTHROW'
801 | requires noexcept(CPP2_UFCS_REMPARENS QUALID __VA_ARGS__(std::declval<Obj>(), std::declval<Params>()...)); }
| ^~~~~~~~~~~
main.cpp2:8:8: note: non-template declaration found by name lookup
8 | auto g {0};
| ^
See https://github.com/hsutter/cppfront/issues/807#issuecomment-1853916877: