std::variant<> and overload resolution

For the test case below, clang+±12 does not emit an error (likely the same on ToT). Nor does g+±9.4.0 with libstdc++. But should they? I suppose “23.7.3.1 Constructors” of C++17 is the relevant specification. Can anyone clarify? I’m not quite sure: is this particular overload resolution issue more of a compiler or library issue?

$ clang++ -fsyntax-only -std=c++17 -x c++ -c test_case.cpp -stdlib=libc++

No. Why do you wonder if they should?
std::variant construction works by “fictitious overload set”: it goes basically as if you’d written
void f(int);
void f(S);
… f(1); …

In the fictitious overload resolution, the int argument is a better match for f(int) than for f(S<A>), so f(int) is chosen. Back in the real world, that means that the variant b is initialized via its int alternative, not its S<A> alternative.
However, this does turn out to get weird when it comes to narrowing conversions, and I haven’t investigated the wording to find out why. Basically

std::variant<int, S> b(int(1)); // initializes the int, duh

std::variant<int, S> b(short(1)); // initializes the int

std::variant<int, S> b(char(1)); // initializes the int

std::variant<int, S> b(long(1)); // initializes the S<A> !?!?!
even though a call to f(long(1)) would resolve to f(int), not f(S<A>).

Finally, btw, note that you wrote S(T&&...) instead of S(T&&). Surprisingly, this is valid C++ syntax, because a trailing ... can mean variadic-function ellipsis instead of parameter-pack-expansion; it’s exactly as if you wrote
S(T&&, …) {}
Since you’re passing only one argument anyway, the trailing ellipsis matches no arguments, contributes nothing to overload resolution, and therefore doesn’t matter at all.

HTH,
Arthur