21
#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.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
ABu
  • 10,423
  • 6
  • 52
  • 103

2 Answers2

12

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's pair base class is a dependent type, so lookup of its constructors cannot succeed. For each specialization of mytype<T1, T2>, the corresponding constructors of pair<T1, T2> are constructors of mytype, 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 of mypair 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:

template<typename T> struct my_pair2 : std::pair<T, T> {
  using pair::pair;
};

What constructors should be notionally injected here? And in cases like this, I think it's reasonably clear that this lookup cannot possibly work:

template<typename T> struct my_pair3 : arbitrary_metafunction<T>::type {
  using arbitrary_metafunction<T>::type::type;
};

It's possible we'll get a rule change to allow deduction through your my_pair and the my_pair2 above if/when we get class template argument deduction rules for alias templates:

template<typename T> using my_pair3 = std::pair<T, T>;
my_pair3 mp3 = {1, 2};

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.

T.C.
  • 133,968
  • 17
  • 288
  • 421
Richard Smith
  • 13,696
  • 56
  • 78
8

See Richard Smith's answer.


A previous version of this answer had stated that the following should work

template <class T> struct B { B(T ) { } };
template <class T> struct D : B<T> { using B<T>::B; };

B b = 4; // okay, obviously
D d = 4; // expected: okay

But this isn't really viable, and wouldn't even be a good idea to work as I thought it would (we inherit the constructors but not the deduction guides?)

Barry
  • 286,269
  • 29
  • 621
  • 977
  • clang has error for both main.cpp:10:16: error: cannot refer to class template 'pair' without a template argument list (void)std::pair(2, 3); // It works ~~~~~^ /usr/include/c++/v1/utility:248:30: note: template is declared here struct _LIBCPP_TYPE_VIS_ONLY pair ^ main.cpp:11:11: error: cannot refer to class template 'mypair' without a template argument list (void)mypair(2, 3); // It doens't work ^ main.cpp:5:8: note: template is declared here struct mypair : std::pair ^ 2 errors generated. – Hariom Singh Oct 23 '17 at 17:00
  • @HariomSingh only clang 5 has support for deduction of class template parameters, which isn't in coliru yet. – ABu Oct 23 '17 at 17:10
  • 2
    I'm inclined to say that this simply should _not_ work. And it most certainly makes no sense to only use the base class's constructors without also using its deduction guides. – T.C. Oct 23 '17 at 18:37
  • @Peregring-lk I use clang 5.0 (on Ubuntu 16.04) and get an error `no viable constructor or deduction guide for deduction of template arguments of ` – user2146414 Feb 16 '18 at 18:18