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

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.

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).)

C++ - Template parameter deduction failed from subclass [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).)

Why are variadic templates different than non-variadic, for only one argument?

This code compiles just fine:
template <typename T1>
struct Struct {
};
struct ConvertsToStruct {
operator Struct<int>() const;
};
template <typename T>
void NonVariadicFunc(Struct<T>);
int main() {
NonVariadicFunc<int>(ConvertsToStruct{});
return 0;
}
But an attempt to make it a little more generic, by using variadic templates, fails to compile:
template <typename T1>
struct Struct {
};
struct ConvertsToStruct {
operator Struct<int>() const;
};
template <typename... T>
void VariadicFunc(Struct<T...>);
int main() {
VariadicFunc<int>(ConvertsToStruct{});
return 0;
}
What's going wrong? Why isn't my attempt to explicitly specify VariadicFunc's template type succeeding?
Godbolt link => https://godbolt.org/g/kq9d7L
There are 2 reasons to explain why this code can't compile.
The first is, the template parameter of a template function can be partially specified:
template<class U, class V> void foo(V v) {}
int main() {
foo<double>(12);
}
This code works, because you specify the first template parameter U and let the compiler determine the second parameter. For the same reason, your VariadicFunc<int>(ConvertsToStruct{}); also requires template argument deduction. Here is a similar example, it compiles:
template<class... U> void bar(U... u) {}
int main() {
bar<int>(12.0, 13.4f);
}
Now we know compiler needs to do deduction for your code, then comes the second part: compiler processes different stages in a fixed order:
cppreference
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before template argument substitution (which may involve SFINAE) and overload resolution.
Implicit conversion takes place at overload resolution, after template argument deduction. Thus in your case, the existence of a user-defined conversion operator has no effect when compiler is doing template argument deduction. Obviously ConvertsToStruct itself cannot match anything, thus deduction failed and the code can't compile.
The problem is that with
VariadicFunc<int>(ConvertsToStruct{});
you fix only the first template parameter in the list T....
And the compiler doesn't know how to deduce the remaining.
Even weirder, I can take the address of the function, and then it works
It's because with (&VariadicFunc<int>) you ask for the pointer of the function (without asking the compiler to deduce the types from the argument) so the <int> part fix all template parameters.
When you pass the ConvertToStruct{} part
(&VariadicFunc<int>)(ConvertToStruct{});
the compiler know that T... is int and look if can obtain a Struct<int> from a ConvertToStruct and find the apposite conversion operator.

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).)