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?
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.)
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With