C++ - Template parameter deduction failed from subclass [duplicate] - c++

I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?

Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)

Related

Overloading operator+() in global scope, for a template class inside a template class [duplicate]

I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?
Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)

Template Template function not deducing arguments as expected [duplicate]

I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?
Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)

Partial template specialization type collapsing rules

Sorry for the lack of a better title.
While trying to implement my own version of std::move and understanding how easy it was, I'm still confused by how C++ treats partial template specializations. I know how they work, but there's a sort of rule that I found weird and I would like to know the reasoning behind it.
template <typename T>
struct BaseType {
using Type = T;
};
template <typename T>
struct BaseType<T *> {
using Type = T;
};
template <typename T>
struct BaseType<T &> {
using Type = T;
};
using int_ptr = int *;
using int_ref = int &;
// A and B are now both of type int
BaseType<int_ptr>::Type A = 5;
BaseType<int_ref>::Type B = 5;
If there wasn't no partial specializations of RemoveReference, T would always be T: if I gave a int & it would still be a int & throughout the whole template.
However, the partial specialized templates seem to collapse references and pointers: if I gave a int & or a int * and if those types match with the ones from the specialized template, T would just be int.
This feature is extremely awesome and useful, however I'm curious and I would like to know the official reasoning / rules behind this not so obvious quirk.
If your template pattern matches T& to int&, then T& is int&, which implies T is int.
The type T in the specialization only related to the T in the primary template by the fact it was used to pattern match the first argument.
It may confuse you less to replace T with X or U in the specializations. Reusing variable names can be confusing.
template <typename T>
struct RemoveReference {
using Type = T;
};
template <typename X>
struct RemoveReference<X &> {
using Type = X;
};
and X& matches T. If X& is T, and T ia int&, then X is int.
Why does the standard say this?
Suppose we look af a different template specialization:
template<class T>
struct Bob;
template<class E, class A>
struct Bob<std::vector<E,A>>{
// what should E and A be here?
};
Partial specializations act a lot like function templates: so much so, in fact, that overloading function templates is often mistaken for partial specialization of them (which is not allowed). Given
template<class T>
void value_assign(T *t) { *t=T(); }
then obviously T must be the version of the argument type without the (outermost) pointer status, because we need that type to compute the value to assign through the pointer. We of course don't typically write value_assign<int>(&i); to call a function of this type, because the arguments can be deduced.
In this case:
template<class T,class U>
void accept_pair(std::pair<T,U>);
note that the number of template parameters is greater than the number of types "supplied" as input (that is, than the number of parameter types used for deduction): complicated types can provide "more than one type's worth" of information.
All of this looks very different from class templates, where the types must be given explicitly (only sometimes true as of C++17) and they are used verbatim in the template (as you said).
But consider the partial specializations again:
template<class>
struct A; // undefined
template<class T>
struct A<T*> { /* ... */ }; // #1
template<class T,class U>
struct A<std::pair<T,U>> { /* ... */ }; // #2
These are completely isomorphic to the (unrelated) function templates value_assign and accept_pair respectively. We do have to write, for example, A<int*> to use #1; but this is simply analogous to calling value_assign(&i): in particular, the template arguments are still deduced, only this time from the explicitly-specified type int* rather than from the type of the expression &i. (Because even supplying explicit template arguments requires deduction, a partial specialization must support deducing its template arguments.)
#2 again illustrates the idea that the number of types is not conserved in this process: this should help break the false impression that "the template parameter" should continue to refer to "the type supplied". As such, partial specializations do not merely claim a (generally unbounded) set of template arguments: they interpret them.
Yet another similarity: the choice among multiple partial specializations of the same class template is exactly the same as that for discarding less-specific function templates when they are overloaded. (However, since overload resolution does not occur in the partial specialization case, this process must get rid of all but one candidate there.)

Template arguments can't be omitted when specializing this function template

In C++, Explicit specializations of function templates is like:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
The <int> in the above example is called template argument. Sometimes <int> can be ommitted because compiler can do Template Argument Deduction
But I can't find out why Template Argument Deduction failed in the following example:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
If no <float> is after fun1, The error message is:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
Let me provide an example of why non-deduced contexts are non-deduced. Template deduction is basically trying to match on the input. If I had:
template <class T> void foo(T );
and I call foo(4), that's easy. T=int. If I call foo('x'), T=char. These are easy substitutions to make. If T is nested somewhere in the type, like:
template <class T> void bar(std::vector<T> );
that's still totally doable. If I call it with a std::vector<std::vector<float>>, T=std::vector<float>. Still no problem.
Now consider this one:
template <class T> void baz(typename X<T>::type );
baz(4);
What's T? In all our previous cases, there was one obvious choice for T that was deduced directly from the argument passed to the function template. But here, that's not the case. We have an extra layer of indirection - we need to deduce a T to make a type X<T> whose member typedef type is int. How do we find such a thing?
Now let's say we had this:
template <class T> struct X { using type = T; };
Ok now it's easy right? T=int? Well, not so fast. For the primary template, that would work in this case. But what if there was also this specialization:
template <class T> struct X<T*> { using type = T; };
(that is, X is std::remove_pointer). Now we're in a situation where T=int works... but T=int* also works. And maybe there's some other type out there that also works for int. How do you pick the right one?
This problem - picking a template parameter in the nested-name specifier of qualified-id - is really hard and has no obvious path forward. So the compiler just won't take a path forward. It's a non-deduced context. T will never be deduced in the call to baz, the caller has to provide it:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
Back to your question. some_struct<T> is a deduced-context, but typename deduce<T>::type is a non-deduced context. I hope it's clear now why the former works but the latter doesn't.
Maybe the compiler think the type(deduce<float>::type) marked by typename is less reliable than normal types ?
It has nothing to do with typename, the point is that deduce<T>::... is a nested-name-specifier; which belongs to Non-deduced contexts:
(emphasis mine)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
So, for
template <>
typename deduce<float>::type fun1()
deduce<float>::type (i.e. float*) will be used to deduce type T for deduce<T>::type, but T won't be deduced, template argument deduction fails. You have to explicitly specify it as float.

What is a nondeduced context?

I've stumbled over "Why is the template argument deduction not working here?" recently and the answers can be summed up to "It's a nondeduced context".
Specifically, the first one says it's such a thing and then redirects to the standard for "details", while the second one quotes the standard, which is cryptic to say the least.
Can someone please explain to mere mortals, like myself, what a nondeduced context is, when does it occur, and why does it occur?
Deduction refers to the process of determining the type of a template parameter from a given argument. It applies to function templates, auto, and a few other cases (e.g. partial specialization). For example, consider:
template <typename T> void f(std::vector<T>);
Now if you say f(x), where you declared std::vector<int> x;, then T is deduced as int, and you get the specialization f<int>.
In order for deduction to work, the template parameter type that is to be deduced has to appear in a deducible context. In this example, the function parameter of f is such a deducible context. That is, an argument in the function call expression allows us to determine what the template parameter T should be in order for the call expression to be valid.
However, there are also non-deduced contexts, where no deduction is possible. The canonical example is "a template parameter that appears to the left of a :::
template <typename> struct Foo;
template <typename T> void g(typename Foo<T>::type);
In this function template, the T in the function parameter list is in a non-deduced context. Thus you cannot say g(x) and deduce T. The reason for this is that there is no "backwards correspondence" between arbitrary types and members Foo<T>::type. For example, you could have specializations:
template <> struct Foo<int> { using type = double; };
template <> struct Foo<char> { using type = double; };
template <> struct Foo<float> { using type = bool; };
template <> struct Foo<long> { int type = 10; };
template <> struct Foo<unsigned> { };
If you call g(double{}) there are two possible answers for T, and if you call g(int{}) there is no answer. In general, there is no relationship between class template parameters and class members, so you cannot perform any sensible argument deduction.
Occasionally it is useful to inhibit argument deduction explicitly. This is for example the case for std::forward. Another example is when you have conversions from Foo<U> to Foo<T>, say, or other conversions (think std::string and char const *). Now suppose you have a free function:
template <typename T> bool binary_function(Foo<T> lhs, Foo<T> rhs);
If you call binary_function(t, u), then the deduction may be ambiguous and thus fail. But it is reasonable to deduce only one argument and not deduce the other, thus permitting implicit conversions. Now an explicitly non-deduced context is needed, for example like this:
template <typename T>
struct type_identity {
using type = T;
};
template <typename T>
bool binary_function(Foo<T> lhs, typename type_identity<Foo<T>>::type rhs)
{
return binary_function(lhs, rhs);
}
(You may have experienced such deduction problems with something like std::min(1U, 2L).)