I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.
Related
I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.
Consider the following MCVE
struct A {};
template<class T>
void test(T, T) {
}
template<class T>
class Wrapper {
using type = typename T::type;
};
template<class T>
void test(Wrapper<T>, Wrapper<T>) {
}
int main() {
A a, b;
test(a, b); // works
test<A>(a, b); // doesn't work
return 0;
}
Here test(a, b); works and test<A>(a, b); fails with:
<source>:11:30: error: no type named 'type' in 'A'
using type = typename T::type;
~~~~~~~~~~~~^~~~
<source>:23:13: note: in instantiation of template class 'Wrap<A>' requested here
test<A>(a, b); // doesn't work
^
<source>:23:5: note: while substituting deduced template arguments into function template 'test' [with T = A]
test<A>(a, b); // doesn't work
LIVE DEMO
Question: Why is that? Shouldn't SFINAE work during substitution? Yet here it seems to work during deduction only.
Self introduction
Hello everyone, I am an innocent compiler.
The first call
test(a, b); // works
In this call, the argument type is A. Let me first consider the first overload:
template <class T>
void test(T, T);
Easy. T = A.
Now consider the second:
template <class T>
void test(Wrapper<T>, Wrapper<T>);
Hmm ... what? Wrapper<T> for A? I have to instantiate Wrapper<T> for every possible type T in the world just to make sure that a parameter of type Wrapper<T>, which might be specialized, can't be initialized with an argument of type A? Well ... I don't think I'm going to do that ...
Hence I will not instantiate any Wrapper<T>. I will choose the first overload.
The second call
test<A>(a, b); // doesn't work
test<A>? Aha, I don't have to do deduction. Let me just check the two overloads.
template <class T>
void test(T, T);
T = A. Now substitute — the signature is (A, A). Perfect.
template <class T>
void test(Wrapper<T>, Wrapper<T>);
T = A. Now subst ... Wait, I never instantiated Wrapper<A>? I can't substitute then. How can I know whether this would be a viable overload for the call? Well, I have to instantiate it first. (instantiating) Wait ...
using type = typename T::type;
A::type? Error!
Back to L. F.
Hello everyone, I am L. F. Let's review what the compiler has done.
Was the compiler innocent enough? Did he (she?) conform to the standard?
#YSC has pointed out that [temp.over]/1 says:
When a call to the name of a function or function template is written
(explicitly, or implicitly using the operator notation), template
argument deduction ([temp.deduct]) and checking of any explicit
template arguments ([temp.arg]) are performed for each function
template to find the template argument values (if any) that can be
used with that function template to instantiate a function template
specialization that can be invoked with the call arguments. For each
function template, if the argument deduction and checking succeeds,
the template-arguments (deduced and/or explicit) are used to
synthesize the declaration of a single function template
specialization which is added to the candidate functions set to be
used in overload resolution. If, for a given function template,
argument deduction fails or the synthesized function template
specialization would be ill-formed, no such function is added to the
set of candidate functions for that template. The complete set of
candidate functions includes all the synthesized declarations and all
of the non-template overloaded functions of the same name. The
synthesized declarations are treated like any other functions in the
remainder of overload resolution, except as explicitly noted in
[over.match.best].
The missing type leads to a hard error. Read https://stackoverflow.com/a/15261234. Basically, we have two stages when determining whether template<class T> void test(Wrapper<T>, Wrapper<T>) is the desired overload:
Instantiation. In this case, we (fully) instantiate Wrapper<A>. In this stage, using type = typename T::type; is problematic because A::type is nonexistent. Problems that occur in this stage are hard errors.
Substitution. Since the first stage already fails, this stage is not even reached in this case. Problems that occur in this stage are subject to SFINAE.
So yeah, the innocent compiler has done the right thing.
I'm not a language lawyer but I don't think that defining a using type = typename T::type; inside a class is, itself, usable as SFINAE to enable/disable a function receiving an object of that class.
If you want a solution, you can apply SFINAE to the Wrapper version as follows
template<class T>
auto test(Wrapper<T>, Wrapper<T>)
-> decltype( T::type, void() )
{ }
This way, this test() function is enabled only for T types with a type type defined inside it.
In your version, is enabled for every T type but gives error when T is incompatible with Wrapper.
-- EDIT --
The OP precises and asks
My Wrapper has many more dependencies on T, it would be impractical to duplicate them all in a SFINAE expression. Isn't there a way to check if Wrapper itself can be instantiated?
As suggested by Holt, you can create a custom type traits to see if a type is a Wrapper<something> type; by example
template <typename>
struct is_wrapper : public std::false_type
{ };
template <typename T>
struct is_wrapper<Wrapper<T>> : public std::true_type
{ using type = T; };
Then you can modify the Wrapper version to receive a U type and check if U is a Wrapper<something> type
template <typename U>
std::enable_if_t<is_wrapper<U>{}> test (U, U)
{ using T = typename is_wrapper<U>::type; }
Observe that you can recover the original T type (if you need it) using the type definition inside the is_wrapper struct.
If you need a non-Wrapper version of test(), with this solution you have to explicity disable it when T is a Wrapper<something> type to avoid collision
template <typename T>
std::enable_if_t<!is_wrapper<T>{}> test(T, T)
{ }
Deduction of the function called in a function call expression is performed in two steps:
Determination of the set of viable functions;
Determination of the best viable function.
The set of viable function can only contain function declaration and template function specialization declaration.
So when a call expression (test(a,b) or test<A>(a,b)) names a template function, it is necessary to determine all template arguments: this is called template argument deduction. This is performed in three steps [temp.deduct]:
Subsitution of explicitly provided template arguments (in names<A>(x,y) A is explicitly provided);(substitution means that in the function template delcaration, the template parameter are replaced by their argument)
Deduction of template arguments that are not provided;
Substitution of deduced template argument.
Call expression test(a,b)
There are no explictly provided template argument.
T is deduced to A for the first template function, deduction fails for the second template function [temp.deduct.type]/8. So the second template function will not participate to overload resolution
A is subsituted in the declaration of the first template function. The subsitution succeeds.
So there is only one overload in the set and it is selected by overload resolution.
Call expression test<A>(a,b)
(Edit after the pertinent remarks of #T.C. and #geza)
The template argument is provided: A and it is substituted in the declaration of the two template functions. This substitution only involves the instantiation of the declaration of the function template specialization. So it is fine for the two template
No deduction of template argument
No substitution of deduced template argument.
So the two template specializations, test<A>(A,A) and test<A>(Wrapper<A>,Wrapper<A>), participate in overload resolution. First the compiler must determine which function are viable. To do that the compiler needs to find an implicit conversion sequence that converts the function argument to the function parameter type [over.match.viable]/4:
Third, for F to be a viable function, there shall exist for each argument an implicit conversion sequence that converts that argument to the corresponding parameter of F.
For the second overload, in order to find a conversion to Wrapper<A> the compiler needs the definition of this class. So it (implicitly) instantiates it. This is this instantiation that causes the observed error generated by compilers.
In his answer to this question and the comment section, Johannes Schaub says there's a "match error" when trying to do template type deduction for a function template that requires more arguments than have been passed:
template<class T>
void foo(T, int);
foo(42); // the template specialization foo<int>(int, int) is not viable
In the context of the other question, what's relevant is whether or not type deduction for the function template succeeds (and substitution takes place):
template<class T>
struct has_no_nested_type {};
// I think you need some specialization for which the following class template
// `non_immediate_context` can be instantiated, otherwise the program is
// ill-formed, NDR
template<>
struct has_no_nested_type<double>
{ using type = double; };
// make the error appear NOT in the immediate context
template<class T>
struct non_immediate_context
{
using type = typename has_no_nested_type<T>::type;
};
template<class T>
typename non_immediate_context<T>::type
foo(T, int) { return {}; }
template<class T>
bool foo(T) { return {}; }
int main()
{
foo(42); // well-formed? clang++3.5 and g++4.8.2 accept it
foo<int>(42); // well-formed? clang++3.5 accepts it, but not g++4.8.2
}
When instantiating the first function template foo for T == int, the substitution produces an invalid type not in the immediate context of foo. This leads to a hard error (this is what the related question is about.)
However, when letting foo deduce its template-argument, g++ and clang++ agree that no instantiation takes place. As Johannes Schaub explains, this is because there is a "match error".
Question: What is a "match error", and where and how is it specified in the Standard?
Altenative question: Why is there a difference between foo(42) and foo<int>(42) for g++?
What I've found / tried so far:
[over.match.funcs]/7 and [temp.over] seem to describe the overload resolution specifics for function templates. The latter seem to mandate the substitution of template parameters for foo.
Interestingly, [over.match.funcs]/7 triggers the process described in [temp.over] before checking for viability of the function template (specialization).
Similarly, type deduction does not to take into account, say, default function arguments (other than making them a non-deduced context). It seems not to be concerned with viability, as far as I can tell.
Another possibly important aspect is how type deduction is specified. It acts on single function parameters, but I don't see where the distinction is made between parameter types that contain / are dependent on template parameters (like T const&) and those which aren't (like int).
Yet, g++ makes a difference between explicitly specifying the template parameter (hard error) and letting them be deduced (deduction failure / SFINAE). Why?
What I've summarized is the process described at 14.8.2.1p1
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.
In our case, we have for P (T, int) and for A, we have (int). For the first pair of P/A, which is T against int, we can match T to int (by the process described in 14.8.2.5). But for the second "pair", we have int but have no counterpart. Thus deduction cannot be made for this "pair".
Thereby, by 14.8.2.5p2, "If type deduction cannot be done for any P/A pair, ..., template
argument deduction fails.".
You then won't ever come to the point where you substitute template arguments into the function template.
This can all probably described more precisely in the Standard (IMO), but I believe this is how one could implement things to match the actual behavior of Clang and GCC and it seems a reasonable interpretation of the Standardese.
I was surprised the following code resulted in a could not deduce template argument for T error:
struct foo
{
template <typename T>
void bar(int a, T b = 0.0f)
{
}
};
int main()
{
foo a;
a.bar(5);
return 0;
}
Calling a.bar<float>(5) fixes the issue. Why can't the compiler deduce the type from the default argument?
In C++03, the specification explicitly prohibits the default argument from being used to deduce a template argument (C++03 §14.8.2/17):
A template type-parameter cannot be deduced from the type of a function default argument.
In C++11, you can provide a default template argument for the function template:
template <typename T = float>
void bar(int a, T b = 0.0f) { }
The default template argument is required, though. If the default template argument is not provided, the default function argument is still not usable for template argument deduction. Specifically, the following applies (C++11 14.8.2.5/5):
The non-deduced contexts are:
...
A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
There would be some technical difficulties in achieving that in general. Remember that default arguments in templates are not instantiated until they are needed. Consider then:
template<typename T, typename U> void f(U p = T::g()); // (A)
template<typename T> T f(long, int = T()); // (B)
int r = f<int>(1);
This is resolved today by performing (among other things) the following steps:
attempt to deduce template parameters for candidates (A) and (B);
this fails for (A), which is therefore eliminated.
perform overload resolution; (B) is selected
form the call, instantiating the default argument
In order to deduce from a default argument, that default argument would have to be itself instantiated before completing the deduction process. That could fail, leading to errors outside the SFINAE context. I.e., a candidate that may be entirely inappropriate for a call could trigger an error.
A good reason might be that
void foo(bar, xyzzy = 0);
is similar to a pair of overloads.
void foo(bar b) { foo(b, 0); }
foo(bar, xyzzy);
Moreover, sometimes it is advantageous to refactor it into such:
void foo(bar b) { /* something other than foo(b, 0); */ }
foo(bar, xyzzy);
Even when written as one, it's still like two functions in one, neither of which is "preferred" in any sense. You're calling the one-argument function; the two-argument one is effectively a different function. The default argument notation just merges them into one.
If overloading were to have the behavior that you are asking for, then for consistency it would have to work in the case when the template is split up into two definitions. That wouldn't make sense because then the deduction would be pulling types from an unrelated function that is not being called! And if it was not implemented, it would mean that overloading different parameter list lengths becomes a "second class citizen" compared to "default-argumenting".
It is good if the difference between overloads and defaulting is completely hidden to the client.
This was motivated by this article (page 5)
template<class T>
T const &f(T const &a, T const &b){
return (a > b ? a : b);
}
template int const &f<int>(int const &, int const &);
int main(){
int x = 0, y = 0;
short s = 0;
f(x, y); // OK
f(x, s); // Is this call well-formed?
}
Is the call 'f(x, s)' well-formed? I assumed that since the function template 'f' is explicitly instantiated, standard conversions would be applied and hence 'short s' would be converted to 'int' to match the call to the explicit specialization 'f<int>'. But it appears that this is ill-formed?
Which part of the Standard talks about the applicable rules in this context?
No, the call f(x, s) is not well-formed. Since you do not explicitly state the specialization to be used, the compiler uses argument deduction to attempt to instantiate the function template; this fails because x and s have different types so T is ambiguous.
The applicable rule is in the specification of the overload resolution process in 13.3.1:
In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way.
14.8.3/1 is also relevant:
For each function template, if the argument deduction and checking succeeds, the template arguments (deduced and/or explicit) are used to instantiate a single function template specialization which is added to the candidate functions set to be used in overload resolution. If, for a given function template, argument deduction fails, no such function is added to the set of candidate functions for that template.
The function template is explicitly instantiated for T = int, but the compiler doesn't know that it should use this instantiation until after it performs template argument deduction to determine what T should be.
The call f(x, s) is syntactically well-formed, but the compiler will not be able to deduce the template parameter T from it because is could a int or a short (because of the first and second arguments). Instantiating the template does not help, that only indicates the compiler to compile that specialization and add it to the generated object file.
If you want the call to cast s to a int automatically, use f<int>(x, s).
An explicitly instantiated specialization doesn't have any higher priority or preferential treatment. It simply exists in its entirety from the point of instantiation. Useful for libraries.
The compiler simply can't figure out which argument to convert, and gets stuck just as it would without the extra declaration.
By the way, if you return it a reference to an argument which was converted, it will be dangling once the temporary expires. If the arguments are references to different types, there is no way to properly form the return value.
Here is my updated min:
#include <type_traits>
template< typename A, typename B >
typename std::common_type< A, B >::type // cannot return ref
my_min( A const &a, B const &b ) {
return a < b? a : b;
}
// enable_if< is_same< A, B > > the old, return-by-reference impl
int main() {
int q = my_min( short(5), long(3) );
}