Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is typename T in call parameter allowed? [duplicate]

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?

like image 305
JeJo Avatar asked Apr 20 '19 20:04

JeJo


1 Answers

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

like image 96
Davis Herring Avatar answered Nov 02 '22 00:11

Davis Herring