A parameter pack appears both empty and non-empty at the same time (original) (raw)
Found a really concerning bug:
template <typename ...P> struct A {};
struct B { consteval B() {} // Making this constexpr makes the assert below pass.
template <typename ...P>
consteval operator A<P...>() const
{
static_assert(sizeof...(P) > 0); // This fails on Clang.
return {};
}
};
template struct type_identity { using type = T; };
template <typename ...P> void foo(typename type_identity<A<P...>>::type a, P...) {}
int main() { foo(B(), 1, 2); }
The static_assert
fires on Clang, meaning it calls operator A<>
with no template arguments! But the corresponding function parameter is A<int, int>
.
Apparently A<>
gets reinterpreted (!!) into A<int, int>
at compile-time. E.g. if you add a int x = sizeof...(P)
data member to it, it'll be 0
despite the type actually being A<int, int>
.
Here's an example of this being used to reinterpret_cast
a float
into an int
: https://gcc.godbolt.org/z/Txbsj8ofM
Tested on Clang 20 and trunk. The only flag needed is -std=c++20
for consteval
.