无参模板函数重载解析的C++20合规性与歧义判定咨询
C++20模板函数重载解析:合法性与歧义判定
在测试模板函数的重载解析时,我发现Clang 15、GCC 12.2、MSVC 19.33等主流C编译器的处理结果存在差异。由于对函数模板重载的细节了解不足,现明确咨询:以下各命名空间中的函数重载,哪些属于合法的C20代码?哪些会触发重载歧义?
一、省略号相关重载(ellipsis)
#e1 | Clang: 通过 | GCC: 歧义 | MSVC: 歧义(主干版本:通过)
namespace e1 { template<typename...> void f(...); template<typename... Ts> void f(Ts...); }
#e2 | Clang: 通过 | GCC: 歧义 | MSVC: 歧义(主干版本:通过)
namespace e2 { template<typename...> void f(...); template<typename..., typename... Ts> void f(Ts...); }
#e3 | Clang: 通过 | GCC: 歧义 | MSVC: 非法且歧义(主干版本:非法)
namespace e3 { template<typename...> void f(...); template<typename... Ts, typename...> void f(Ts...); }
#e4 | Clang: 通过 | GCC: 歧义 | MSVC: 非法且歧义(主干版本:非法)
namespace e4 { template<typename..., typename...> void f(...); template<typename... Ts> void f(Ts...); }
#e5 | Clang: 歧义 | GCC: 歧义 | MSVC: 歧义(主干版本:通过)
namespace e5 { template<typename... Ts> void f(Ts..., ...); template<typename... Ts> void f(Ts...); }
#e6 | Clang: 通过 | GCC: 歧义 | MSVC: 歧义
namespace e6 { template<typename... Ts> void f(Ts..., ...); template<typename...> void f(...); }
二、默认参数相关重载(defaulted argument)
#d1 | Clang: 通过(主干版本:歧义) | GCC: 通过 | MSVC: 歧义(主干版本:通过)
namespace d1 { template<typename...> void f(bool = true); template<typename... Ts> void f(Ts...); }
#d2 | Clang: 通过(主干版本:歧义) | GCC: 通过 | MSVC: 非法且歧义(主干版本:非法)
namespace d2 { template<typename...> void f(bool = true); template<typename... Ts, typename...> void f(Ts...); }
#d3 | Clang: 通过(主干版本:歧义) | GCC: 通过 | MSVC: 歧义(主干版本:通过)
namespace d3 { template<typename...> void f(bool = true); template<typename..., typename... Ts> void f(Ts...); }
#d4 | Clang: 歧义(主干版本:通过) | GCC: 通过 | MSVC: 通过
namespace d4 { template<typename...> void f(bool = true); template<typename... Ts, typename... Us> void f(Ts..., Us...); }
#d5 | Clang: 歧义 | GCC: 通过 | MSVC: 非法
namespace d5 { template<typename...> void f(bool = true); template<typename... Ts, typename...> void f(Ts..., ...); }
#d6 | Clang: 通过(主干版本:歧义) | GCC: 通过 | MSVC: 非法且歧义(主干版本:非法且歧义)
namespace d6 { template<typename...> void f(bool = true); template<typename..., typename... Ts> void f(Ts..., ...); }
#d7 | Clang: 通过 | GCC: 歧义 | MSVC: 通过
namespace d7 { template<typename...> void f(bool = true); template<typename... Ts> void f(bool = true, Ts...); }
#d8 | Clang: 通过 | GCC: 歧义 | MSVC: 歧义(主干版本:通过)
namespace d8 { template<typename...> void f(bool = true, ...); template<typename... Ts> void f(bool = true, Ts...); }
测试结果概览
| 测试用例 | Clang 15 | Clang 主干版本 | GCC 12.2 | GCC 主干版本 | MSVC 19.33 | MSVC 主干版本 |
|---|---|---|---|---|---|---|
| #e1 | 通过 | 通过 | 歧义 | 歧义 | 歧义 | 通过 |
| #e2 | 通过 | 通过 | 歧义 | 歧义 | 歧义 | 通过 |
| #e3 | 通过 | 通过 | 歧义 | 歧义 | 非法且歧义 | 非法 |
| #e4 | 通过 | 通过 | 歧义 | 歧义 | 非法且歧义 | 非法 |
| #e5 | 歧义 | 歧义 | 歧义 | 歧义 | 歧义 | 通过 |
| #e6 | 通过 | 通过 | 歧义 | 歧义 | 歧义 | 通过 |
| #d1 | 通过 | 歧义 | 通过 | 通过 | 歧义 | 通过 |
| #d2 | 通过 | 歧义 | 通过 | 通过 | 非法且歧义 | 非法 |
| #d3 | 通过 | 歧义 | 通过 | 通过 | 歧义 | 通过 |
| #d4 | 歧义 | 通过 | 通过 | 通过 | 通过 | 通过 |
| #d5 | 歧义 | 歧义 | 通过 | 通过 | 非法 | 非法 |
| #d6 | 通过 | 歧义 | 通过 | 通过 | 非法且歧义 | 非法且歧义 |
| #d7 | 通过 | 通过 | 歧义 | 歧义 | 通过 | 通过 |
| #d8 | 通过 | 通过 | 歧义 | 歧义 | 歧义 | 通过 |
错误信息示例
Clang 15 在测试用例 d4 中的错误:
<source>:135:28: error: call to 'f' is ambiguous static_assert(not noexcept(f())); ^ <source>:89:10: note: candidate function [with $0 = <>] void f(bool = true); ^ <source>:92:10: note: candidate function [with Ts = <>, Us = <>] void f(Ts..., Us...); ^
GCC 12.2 在测试用例 d7 中的错误:
<source>:135:29: error: call of overloaded 'f()' is ambiguous 135 | static_assert(not noexcept(f())); | ~^~ <source>:116:10: note: candidate: 'void d7::f(bool) [with <template-parameter-1-1> = {}]' 116 | void f(bool = true); | ^ <source>:119:10: note: candidate: 'void d7::f(bool, Ts ...) [with Ts = {}]' 119 | void f(bool = true, Ts...); | ^
MSVC 19.33 在测试用例 e3 中的错误:
<source>(27): error C3547: template parameter '<unnamed-symbol>' cannot be used because it follows a template parameter pack and cannot be deduced from the function parameters of 'e3::f' <source>(27): note: see declaration of '<unnamed-symbol>' <source>(135): error C2668: 'e3::f': ambiguous call to overloaded function <source>(27): note: could be 'void e3::f<,>(void)' <source>(24): note: or 'void e3::f<>(...)' <source>(135): note: while trying to match the argument list '()' <source>(135): error C2056: illegal expression <source>(135): error C2607: static assertion failed
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

