As I understand it, the following should be valid C 20:
template<int i> struct A {};
struct B
{
constexpr int one() const { return 1; }
};
template<B b> A<b.one()> f() { return {}; }
void test()
{
f<B{}>();
}
MSVC does not like this (Visual Studio 2022, but godbolt appears to show all versions failing in some way, including an ICE for v19.28):
error C2672: 'f': no matching overloaded function found
error C2770: invalid explicit template argument(s) for 'A<'function'> f(void)'
Both clang and gcc accept it though.
As a workaround, wrapping the function evaluation works fine:
template<B b>
struct WrapOne
{
static constexpr int value = b.one();
};
template<B b> A<WrapOne<b>::value> f() { return {}; }
Wrapping via an inline constexpr variable also works:
template<B b> inline constexpr auto one_v = b.one();
template<B b> A<one_v<b>> f() { return {}; }
I'm assuming that this is a bug in MSVC? I couldn't find anything relevant on the MS Developer Community site, but it feels like a pretty fundamental thing that other people must have come across.
Any other clever workarounds?
CodePudding user response:
Yes, seems like a bug to me as well.
The parser seems to have a problem specifically with the member function call via .
in the template argument. It works when using ->
:
template<B b> A<(&b)->one()> f() { return {}; }
CodePudding user response:
MSVC is wrong in rejecting the code as the program is well-formed since b.one()
is a valid non-type template argument.
This bug has been reported here.