Search code examples
c++constructor

Unexpected infinite recursion in C++ constructors


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?


Solution

  • 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.