Date: Sun, 12 Jul 2026 07:59:07 +0000
By the text of the standard, it would suggest that you have a point. But the syntax did not make it easy for the compiler vendors.
________________________________
From: Std-Discussion <std-discussion-bounces_at_[hidden]> on behalf of SD SH via Std-Discussion <std-discussion_at_[hidden]>
Sent: Sunday, 12 July 2026 08:50:56
To: Deslauriers, Douglas via Std-Discussion <std-discussion_at_[hidden]>
Cc: SD SH <Z5515zwy_at_[hidden]>
Subject: [std-discussion] a doubt about getting the pointer of a function name with function templates
Hi.
1. Intro
```
template<typename...>
void foo() { }
auto _ = &foo; // is it OK?
```
GCC, Clang and MSVC have different results of it:
GCC: [success]
Clang: error: variable '_' with type 'auto' has incompatible initializer of type '<overloaded function type>'
MSVC: error C3535: cannot deduce type for 'auto' from 'overloaded-function'
2. My Opinion
The type of `_` is `decltype(&foo)` [a],
`&foo` can be deduced as `&foo<>` here [b], and have a unique function.
So `&foo` should be deduced as `void foo<>(void)` [c], then `decltype(&foo)` is `void(*)(void)`.
Therefore, the code is expected to be:
```
template<typename...>
void foo(void) { }
template<>
void foo<>(void) { } // implicit specialization by `foo`
void(*_)(void) = static_cast<void(*)(void)>(&foo<>);
```
By the text of Standard, seems it is well-formed, or I made some mistakes on it.
The compilers didn't have the same behaviors. Is the code correct?
3. Compilers Have Different Behaviors of Same Expressions
The 3 compilers all accepted these code:
```
template<typename...>
int foo(void) { return 0; }
auto _ = (&foo)();
```
It shows that all the compilers can accept `&foo` as `&foo<>`.
If it is true, both Clang and MSVC has different behaviors of the expression `&foo`.
While the 3 compilers all rejected these code:
```
template<typename...>
int foo(void) { return 0; }
using X = decltype(&foo);
```
So, GCC also has different behaviors of the expression `&foo`.
Overall, all of GCC, MSVC and Clang has different behaviors of the expression `&foo`.
I doubt the all these compilers didn't follow the Standard, or the Standard itself have ambiguities in some places.
4. References:
[a] [dcl.type.auto.deduct]-p1
Placeholder type deduction is the process by which a type containing a placeholder type is replaced by a deduced type.
[b] [temp.arg.explicit]-p4
Trailing template arguments that can be deduced ([temp.deduct]) or obtained from default template-arguments may be omitted from the list of explicit template-arguments.
[Note 1: A trailing template parameter pack ([temp.variadic]) not otherwise deduced will be deduced as an empty sequence of template arguments. — end note]
If all of the template arguments can be deduced or obtained from default template-arguments, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
[c] [expr.prim.id.general]-p6
For an id-expression that denotes an overload set, overload resolution is performed to select a unique function ([over.match], [over.over]).
[d] [over.over]-p1
... [Note 1: Any redundant set of parentheses surrounding the function name is ignored ([expr.prim.paren]). — end note]
[e] CWG 2848. Omitting an empty template argument list for explicit instantiation
5. Others
The text of the Standard is cited from https://eel.is/c++draft/ .
All the compiler behaviors of code above are given by Godbolt.
GCC: x86-64 gcc 16.1 with command `-std=c++23`
Clang: x86-65 clang 22.1.0 with command `-std=c++23`
MSVC: x64 msvc v19.51 VS18.6 with command `/std:c++latest`
________________________________
From: Std-Discussion <std-discussion-bounces_at_[hidden]> on behalf of SD SH via Std-Discussion <std-discussion_at_[hidden]>
Sent: Sunday, 12 July 2026 08:50:56
To: Deslauriers, Douglas via Std-Discussion <std-discussion_at_[hidden]>
Cc: SD SH <Z5515zwy_at_[hidden]>
Subject: [std-discussion] a doubt about getting the pointer of a function name with function templates
Hi.
1. Intro
```
template<typename...>
void foo() { }
auto _ = &foo; // is it OK?
```
GCC, Clang and MSVC have different results of it:
GCC: [success]
Clang: error: variable '_' with type 'auto' has incompatible initializer of type '<overloaded function type>'
MSVC: error C3535: cannot deduce type for 'auto' from 'overloaded-function'
2. My Opinion
The type of `_` is `decltype(&foo)` [a],
`&foo` can be deduced as `&foo<>` here [b], and have a unique function.
So `&foo` should be deduced as `void foo<>(void)` [c], then `decltype(&foo)` is `void(*)(void)`.
Therefore, the code is expected to be:
```
template<typename...>
void foo(void) { }
template<>
void foo<>(void) { } // implicit specialization by `foo`
void(*_)(void) = static_cast<void(*)(void)>(&foo<>);
```
By the text of Standard, seems it is well-formed, or I made some mistakes on it.
The compilers didn't have the same behaviors. Is the code correct?
3. Compilers Have Different Behaviors of Same Expressions
The 3 compilers all accepted these code:
```
template<typename...>
int foo(void) { return 0; }
auto _ = (&foo)();
```
It shows that all the compilers can accept `&foo` as `&foo<>`.
If it is true, both Clang and MSVC has different behaviors of the expression `&foo`.
While the 3 compilers all rejected these code:
```
template<typename...>
int foo(void) { return 0; }
using X = decltype(&foo);
```
So, GCC also has different behaviors of the expression `&foo`.
Overall, all of GCC, MSVC and Clang has different behaviors of the expression `&foo`.
I doubt the all these compilers didn't follow the Standard, or the Standard itself have ambiguities in some places.
4. References:
[a] [dcl.type.auto.deduct]-p1
Placeholder type deduction is the process by which a type containing a placeholder type is replaced by a deduced type.
[b] [temp.arg.explicit]-p4
Trailing template arguments that can be deduced ([temp.deduct]) or obtained from default template-arguments may be omitted from the list of explicit template-arguments.
[Note 1: A trailing template parameter pack ([temp.variadic]) not otherwise deduced will be deduced as an empty sequence of template arguments. — end note]
If all of the template arguments can be deduced or obtained from default template-arguments, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.
[c] [expr.prim.id.general]-p6
For an id-expression that denotes an overload set, overload resolution is performed to select a unique function ([over.match], [over.over]).
[d] [over.over]-p1
... [Note 1: Any redundant set of parentheses surrounding the function name is ignored ([expr.prim.paren]). — end note]
[e] CWG 2848. Omitting an empty template argument list for explicit instantiation
5. Others
The text of the Standard is cited from https://eel.is/c++draft/ .
All the compiler behaviors of code above are given by Godbolt.
GCC: x86-64 gcc 16.1 with command `-std=c++23`
Clang: x86-65 clang 22.1.0 with command `-std=c++23`
MSVC: x64 msvc v19.51 VS18.6 with command `/std:c++latest`
Received on 2026-07-12 07:59:11
