Why are the following two templates incompatible and can't be overloaded?
#include <vector>
template<typename T>
auto f(T t) { return t.size(); }
template<typename T>
auto f(T t) { return t.foobar(); }
int main() {
f(std::vector<int>());
}
I would think they are (more or less) equivalent with the following which compiles fine (as we cannot do decltype auto(t.size())
I can't give an exact equivalent without some noise..).
template<typename T>
auto f(T t) -> decltype(t.size() /* plus some decay */) { return t.size(); }
template<typename T>
auto f(T t) -> decltype(t.foobar() /* plus some decay */) { return t.foobar(); }
Clang and GCC complain main.cpp:6:16: error: redefinition of 'f'
if I leave off the trailing return type, however.
(Note that this is a rationale question. I am not seeking for the place in the Standard which defines this behavior - which you may include in your answer too, if you wish - but for an explanation of why this behavior is desirable or status-quo).
In C++14, you can just use auto as a return type.
Type inference or deduction refers to the automatic detection of the data type of an expression in a programming language. It is a feature present in some strongly statically typed languages. In C++, the auto keyword(added in C++ 11) is used for automatic type deduction.
C++: “auto” return type deduction The “auto” keyword used to say the compiler: “The return type of this function is declared at the end”. In C++14, the compiler deduces the return type of the methods that have “auto” as return type. Restrictions: All returned values must be of the same type.
The deduced return type can clearly not be part of the signature.
However, inferring an expression that determines the return type (and participates in SFINAE) from return
statements has some issues. Let's say we were to take the first return
statement's expression and paste it into some adjusted, virtual trailing-return-type:
What if the returned expression depends on local declarations? This isn't necessarily stopping us, but it snarls the rules tremendously. Don't forget that we can't use the names of the entities declared; This could potentially complex our trailing-return-type sky-high for potentially no benefit at all.
A popular use case of this feature are function templates returning lambdas. However, we can hardly make a lambda part of the signature - the complications that would arise have been elaborated on in great detail before. Mangling alone would require heroic efforts. Hence we'd have to exclude function templates using lambdas.
The signature of a declaration couldn't be determined if it wasn't a definition also, introducing a whole set of other problems. The easiest solution would be to disallow (non-defining) declarations of such function templates entirely, which is almost ridiculous.
Fortunately the author of N3386 strove to keep the rules (and implementation!) simple. I can't imagine how not having to write a trailing-return-type yourself in some corner cases warrants such meticulous rules.
I think that may be commitee miss but backstory I believe is the following:
You cannot overload over the function return type. This means that in declaration
template<typename T>
auto f(T t) { return t.size(); }
Value of auto
is not interesting to compiler in fact until function instantiation. Obviously compiller does not add some SFINAE check to the function body to check if T::size
exist as it does not in all other cases when T
is used inside function body
When generating overloads compiler will check if two function signatures are exact equivalent taking in mind all possible substitutions.
In the first case then compiler will get smth like
[template typename T] f(T)
[template typename T] f(T)
That are exact equivalent
In the second case however as decltype
specified explicitly it will be added to the template arguments so you'll get
[template typename T, typename = typeof(T::size())] f(T)
[template typename T, typename = typeof(T::size())] f(T)
That are not exact equivalents obviously.
So compiler will refuse the first case while second could be OK when substituting real type instead of T
.
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