#include <utility>
template<class T1, class T2>
struct mypair : std::pair<T1, T2>
{ using std::pair<T1, T2>::pair; };
int main()
{
(void)std::pair(2, 3); // It works
(void)mypair(2, 3); // It doesn't work
}
Is the above well formed?
Is it possible deduce the class template arguments in the second case if the constructors are being inherited? Are the constructors of std::pair
participating in the creation of implicit deduction guides for mypair
?
My compiler is g++ 7.2.0.
The short story: there is no rule in the standard that says how this would work, nor any rule that says that it doesn't work. So GCC and Clang conservatively reject rather than inventing a (non-standard) rule.
The long story:
mypair
'spair
base class is a dependent type, so lookup of its constructors cannot succeed. For each specialization ofmytype<T1, T2>
, the corresponding constructors ofpair<T1, T2>
are constructors ofmytype
, but this is not a rule that can be meaningfully applied to a template prior to instantiation in general.In principle, there could be a rule that says that you look at the constructors of the primary
pair
template in this situation (much as we do when looking up constructors ofmypair
itself for class template argument deduction), but no such rule actually exists in the standard currently. Such a rule quickly falls down, though, when the base class becomes more complex:What constructors should be notionally injected here? And in cases like this, I think it's reasonably clear that this lookup cannot possibly work:
It's possible we'll get a rule change to allow deduction through your
my_pair
and themy_pair2
above if/when we get class template argument deduction rules for alias templates:The complexities involved here are largely the same as in the inherited constructor case. Faisal Vali (one of the other designers of class template argument deduction) has a concrete plan for how to make such cases work, but the C++ committee hasn't discussed this extension yet.
I think this is a gcc bug (or at least a minor core language wording defect).
Inherited constructors do count as constructors, according to [namespace.udecl]/16:
That list of conditions technically doesn't include [over.match.class.deduct], but the implication is that the base class constructors are constructors of the derived class. And the rule in [over.match.class.deduct] is to consider:
We are looking up constructors of the derived class, just not in any of the listed cases. But this example should work conceptually: