3

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?

6
  • 1
    It's not a compliler bug, you have allowed implicit conversions. Declare the constructors explicit. Commented Dec 26, 2023 at 7:08
  • @273K I don't think explicit will solve the issue, since the void constructor_impl method is private, and not an actual constructor. Try to better the define the actual (public) constructor, and not make it as general (i.e., without auto). Commented Dec 26, 2023 at 7:31
  • @Amit What do you mean? The member functions constructor_impl are not constructors. Making the only constructor explicit makes the code ill-formed, as it's desired. Commented Dec 26, 2023 at 7:46
  • 2
    What constructor_impl do you expect A{""} to use? "" isn't convertible to int, so converting it to A seems to be the only possible way out. Commented Dec 26, 2023 at 8:02
  • A suggestion to title, add due to implicit conversion might help future reader. Commented Dec 26, 2023 at 8:21

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.