A minimal example is:
#include <vector>
class A {
private:
// where the real initialization happens
void constructor_impl(int);
void constructor_impl(const A&);
public:
A(const auto&... args) {
(constructor_impl(args), ...);
}
};
int main() {
A{0, A{1, 2}}; // correct construction
A{""}; // wrong construction: compiles to an infinite recursion
}
I expect the wrong call A{""} to raise a compile error. But instead the compiler tries to cast "" to A and generates an infinite recursion. GCC, Clang and MSVC generates similar results, so it's unlikely to be a compiler bug.
Why does it happen? How can I refactor my code to avoid this issue?
Your templated constructor is effectively a single argument constructor which accepts arguments of any type, therefore any type is implicitly convertible to A. Therefore when A is passed any argument which isn't int or A the compiler will attempt to call void constructor_impl(const A&); via an implicit conversion. As you say this leads to infinite recursion.
To avoid this problem you should mark the constructor as explicit:
explicit A(const auto&... args) {
This will prevent any implicit conversions to A and give you the compiler error you expect. In general, all single argument constructors should be marked explicit to avoid surprising implicit conversions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With