使用using导入构造函数为何会导致重载决议选择不同的重载版本?
using Base::Base change overload resolution for Derived's constructors? Great question! The behavior you're seeing comes down to a specific rule in C++ about inherited constructors (those imported via using declarations) and how they interact with compiler-generated special member functions. Let's break this down step by step.
What's happening when you explicitly declare Derived's constructors (#if 1)
When you write:
Derived(const Base& other) : Base(other) {} Derived(const BaseBase& other) : Base(other) {}
You're explicitly defining two constructors for Derived:
Derived(const Base&): Takes aconst Base&and forwards it toBase's copy constructor (which setstest = 1).Derived(const BaseBase&): Takes aconst BaseBase&and forwards it toBase's constructor that takesconst BaseBase&(which setstest = 2).
When you call Derived d1{b1} where b1 is a Base, overload resolution picks the exact match (const Base&), so test is set to 1—this matches your expectation.
What changes when you use using Base::Base (#if 0)
When you import base class constructors with using Base::Base, C++ applies some important rules that you might not be aware of:
1. Compiler-generated copy constructor blocks importing Base's copy constructor
The C++ standard states that inherited constructors (from using declarations) are not imported if they would conflict with a special member function that the compiler generates automatically for the derived class.
In your case, since you didn't declare a copy constructor for Derived, the compiler generates a default copy constructor:
Derived(const Derived&) = default;
This generated copy constructor counts as a "corresponding copy constructor" to Base's copy constructor (Base(const Base&)). As a result, the Base(const Base&) constructor is not imported into Derived.
2. Only non-conflicting base constructors are imported
The only constructors imported into Derived are:
Derived(): FromBase's default constructor.Derived(const BaseBase&): FromBase's constructor takingconst BaseBase&(since there's no conflicting compiler-generated constructor for this signature).
3. Overload resolution has no exact match
When you call Derived d1{b1} now, there's no Derived(const Base&) constructor available (it wasn't imported). The only candidate is Derived(const BaseBase&), which accepts b1 via a derived-to-base conversion (since Base inherits from BaseBase). This constructor forwards to Base(const BaseBase&), setting test = 2—hence your return value of 2.
Summary of the key rule
When using using Base::Base to inherit constructors:
- Inherited constructors that would act as the derived class's default, copy, or move constructor are not imported if the compiler generates that special member function automatically.
- This means
Base's copy constructor doesn't become part ofDerived's overload set, leaving only theBaseBase&constructor to handle theBaseargument via conversion.
内容的提问来源于stack exchange,提问作者JacquesH

