Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deducing class template arguments with a constructor that uses a member type alias

So apparently this is supposed to work:

template<class T>
struct C {
   using value_type = T;
   C(value_type);
};

C c(1); // C<int>

As is this (see the B example in [over.match.class.deduct]/3):

template<class T>
struct D {
   template<class> using meow_t = T;

   template<class U>
   D(U, meow_t<U>);
};

D d(1, 'c'); // D<char>

Note that a seemingly-equivalent explicit guide won't work since the parameter is a non-deduced context:

template<class T>
C(typename C<T>::value_type) -> C<T>;

While it's certainly desirable that at least the first snippet works, I haven't yet been able to find the wording that actually makes it work in the current working draft. Does anyone know where it is?

like image 431
T.C. Avatar asked Apr 20 '17 21:04

T.C.


People also ask

What are template arguments enlist types of template arguments?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

What is template argument deduction in C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.

What is a template template parameter in C++?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

Which of the following types Cannot be used for a non type template parameter?

Non-type template parameters are one of the few places in C++ where a visible distinction is made between class types and others: integral types, enum types, pointer types, point- to-member types, reference types and std::nullptr_t can all be used as non-type template parameters, but class types cannot.


1 Answers

This isn't strictly an answer, as I don't think such wording actually exists. This is more of a cobbling together of information related to the question.


This is Core Issue 2. The discussion in Oulu and Issaquah about this feature made it clear that the intent is that looking through the typedefs is valid, but no wording as added to indicate as to how this is supposed to work - it just... is. The wording as-is suggests that the deduction guide for:

template<class T>
struct C {
   using value_type = T;
   C(value_type);
};

would be:

template <class T> C<T> foo(typename C<T>::value_type );

which would be a non-deduced context and fail, yet [thread.lock.guard] does not have an explicit deduction guide for this case.

The example in [over.match.best] is apparently intended to indicate that typedefs are supposed to work, although none of the examples in that example actually use #1 as the deduction guide:

template <class T> struct A {
  using value_type = T;
  A(value_type);    // #1
  A(const A&);      // #2
  A(T, T, int);     // #3
  template<class U>
    A(int, T, U);   // #4
  // #5 is the copy deduction candidate, A(A)
};

A x(1, 2, 3);       // uses #3, generated from a non-template constructor

template <class T>
A(T) -> A<T>;       // #6, less specialized than #5

A a(42);            // uses #6 to deduce A<int> and #1 to initialize
A b = a;            // uses #5 to deduce A<int> and #2 to initialize

template <class T>
A(A<T>) -> A<A<T>>; // #7, as specialized as #5

A b2 = a;           // uses #7 to deduce A<A<int>> and #1 to initialize
like image 62
Barry Avatar answered Oct 13 '22 04:10

Barry