Sorry, I couldn't make a better title for this issue.
I have written a code for this SO post; which look likes:
#include <iostream>
#include <string>
#include <type_traits>
template < typename T, typename ...Ts> T f(const T &a, Ts&&... args)
{
return a;
}
template < typename R, typename T, typename... Ts>
typename std::enable_if<!std::is_same<R, T>::value, R>::type
f(typename T, Ts&&... args)
//^^^^^^^^^^ --->HERE
{
return f<R>(std::forward<Ts>(args)...);
}
int main() {
std::cout << f<int>('a', std::string{ "string" }, 12);
return 0;
}
There you can see, I have made a typo(presumably)
f(typename T, Ts&&... args)
//^^^^^^^^^^
However, the code compies with msvc v19.14 when -O3 -std=c++11
.
On the other hand, GCC and clang provide compiler errors: https://godbolt.org/z/HugROb
from GCC:
error : 'template<class R, class T, class ... Ts> typename std::enable_if<(! std::is_same< <template-parameter-1-1>, <template-parameter-1-2> >::value), R>::type f' conflicts with a previous declaration
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^ ~~~~~~~
note : previous declaration 'T f(T, Ts&& ...)'
template < typename T, typename ...Ts> T f(T a, Ts&&... args)
^
error : expected nested - name - specifier before 'T'
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^
error : expected '(' before 'T'
error : expected primary - expression before '&&' token
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^ ~
warning : variable templates only available with - std = c++14 or -std = gnu++14
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^
error : expected ';' before '{' token
{
^
From clang:
<source>:13 : 74 : error : expected a qualified name after 'typename'
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^
<source> : 13 : 74 : error : expected a qualified name after 'typename'
<source> : 13 : 74 : error : expected ')'
<source> : 13 : 64 : note : to match this '('
typename std::enable_if<!std::is_same<R, T>::value, R>::type f(typename T, Ts&&... args)
^
<source> : 15 : 34 : error : use of undeclared identifier 'args'; did you mean 'abs' ?
return f<R>(std::forward<Ts>(args)...);
^~~~
abs
/ usr / include / stdlib.h:837 : 12 : note : 'abs' declared here
extern int abs(int __x) __THROW __attribute__((__const__)) __wur;
^
Is it really allowed to have so? or is it a bug in the msvc compiler?
The parser guide typename
can appear only before a qualified name (that is, with a ::
). It could never be needed before an unqualified name because such names must refer to some known declaration and are thus known to refer to types if they do.
GCC and Clang say this pretty explicitly (although each also produces less useful errors in attempting to recover from the bad parse).
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