cplusplus / CWG

Core Working Group
23 stars 7 forks source link

Variable template or function template declaration using alias template for function type #518

Closed ranaanoop closed 6 months ago

ranaanoop commented 6 months ago

Full name of submitter: Anoop Rana

Reference (section label):

Issue description:

The following program shows implementation divergence.

template <typename N>
void func(N a);    //a function template

template <typename N>
using ForceType = decltype(func<N>); //alias for function template

template <typename N>
ForceType<N> force2;  //is this a variable template as msvc suggest or function declaration

template <typename N>  void force2<N>(N)    //msvc accepts this but not gcc and clang
{} 

// template <typename N>  void force2(N)    //None accept this: note the missing template argument list here, msvc says "previous definition was data variable"
// {}

It is not clear if force2 is supposed to be a variable template or a function declaration.

frederick-vs-ja commented 6 months ago

The divergence is probably from a bug of MSVC. Actually, all 3 compilers currently treat force2 as a variable template (Godbolt link).

#include <typeinfo>
#include <cstdio>

template <typename T>
void func(T);    // a function template

template <typename T>
using WithDecltype = decltype(func<T>); // alias for function type

template <typename T>
WithDecltype<T> force2;  // All 3 compilers think this is an invalid variable template.

template <typename T>
using WithExplicitDeclarator = void(T); // alias for function type

template <typename T>
WithExplicitDeclarator<T> force3; // valid function template

template<auto V>
struct type_tag {};

int main()
{
    std::puts(typeid(type_tag<force2<char>>).name()); // rejected
    std::puts(typeid(type_tag<force3<char>>).name()); // accepted
}

I failed to find why force2 is problematic. Perhaps [temp.type] p4 is related.

ranaanoop commented 6 months ago

all 3 compilers currently treat force2 as a variable template

@frederick-vs-ja No, they don't. See the error messages(from gcc and clang) in this demo which explicitly say that error: variable 'force2' has function type. I did checked this before posting the original issue also. Did I miss something?


For reference, here is the code that shows that gcc and clang considers force2 to be a function type while msvc considers it a variable template.

template <typename N>
void func(N a);    

template <typename N>
using ForceType = decltype(func<N>); 

template <typename N>
ForceType<N> force2; 

constexpr int i = force2<int>; //gcc and clang says force2 has function type but msvc says a specialization of variable template cannot have type void (N)

GCC says:

<source>:9:14: error: variable 'force2' has function type
    9 | ForceType<N> force2;
      |              ^~~~~~

While msvc says:

<source>(11): error C7532: 'force2': a specialization of variable template cannot have type 'void (N)'
        with
        [
            N=int
        ]
<source>(11): error C2440: 'initializing': cannot convert from 'void (N)' to 'const int'
        with

While clang says:

error: variable instantiated with function type 'ForceType<int>' (aka 'void (int)')
    9 | ForceType<N> force2; 
      |              ^
<source>:11:19: note: in instantiation of variable template specialization 'force2' requested here
   11 | constexpr int i = force2<int>; 
frederick-vs-ja commented 6 months ago

For reference, here is the code that shows that gcc and clang considers force2 to be a function type while msvc considers it a variable template.

No, they consider the type of force2 to be a function type. Per these error messages, gcc and clang also consider the specialization of force2 a variable. They are just omitting the "template" part in the diagnostics.

IIRC all 3 compilers agree on that

CWG2862 may be related - the proposed resolution attempts to make distinction between function templates and variable templates.

  • A function template is introduced by a template-declaration whose declaration declares a function.
  • [...]
  • A variable template is introduced by a template-declaration whose declaration declares a variable.

However, the type in the declaration may be a dependent type that is "not obviously a function type or not", and may be conditionally a function type or an object type.

Perhaps we should address such edge cases. @jensmaurer

jensmaurer commented 6 months ago

A dependent type can't turn a (syntactic) variable declaration into a function declaration at instantiation time: temp.spec.general p8.

frederick-vs-ja commented 6 months ago

So is it intended not to disambiguate function and variable templates in the proposed resolution of CWG2862 because ambiguous cases are ill-formed?

jensmaurer commented 6 months ago

Yes. If the declaration syntactically declares a variable, it can't declare a function (template) later.