c++ - 避免在人为的模棱两可的重载函数调用中拼写出类型
问题描述
最小示例程序:
#include <vector>
void f(std::vector<int>) {} // #1
void f(std::vector<void *>) {} // #2
int main() { f({ 1 }); }
直觉上,这是一个有效的程序是有意义的:使用重载#1 的调用将是有效的,使用重载#2 的调用将是格式错误的,因此应该选择重载#1。这就是 clang 所做的。
不幸的是,按照标准,这似乎是模棱两可的,因为有一个构造函数std::vector<void *>
可以用 调用int
,通过隐式将其转换为size_t
。explicit
在重载决议期间应该忽略该构造函数的事实,如果选择该重载,程序将只是格式错误。GCC 以模棱两可的方式拒绝该呼叫,并且这样做看起来是正确的。
我可以修改代码,让 GCC 通过拼写类型名称来接受调用:f(std::vector<int>{ 1 });
。我也可以使用带有默认参数的标签调度来明确指定要使用的重载,同时允许像以前一样接受现有调用。
这两个都是可以接受的,但是当回到真实代码时会很快变得相当冗长。是否有另一个选项可以让我避免拼出完整的类型名称,但坚持使用当前的重载?我想了一会儿{ 1, }
可能会起作用,但当然它不会,int i = { 1, };
也是完全有效的,不能用来避免#2。
如果有助于排除某些替代方案,则实际代码确实涉及std::vector<int>
并且std::vector<T>
确实涉及使用包含单个整数表达式的花括号初始化列表的调用,但T
它是用户定义的类型,而不是内置类型,并且表达式是不是一个常数值。
“否”是可以接受的答案,但在这种情况下,请详细说明,请表明没有这样的选项。
解决方案
总是很难证明是否定的,但考虑到引入的可能性
using I=std::vector<int>;
我认为您真的在问“有没有办法避免标准转换以size_type
消除争用中的其他重载”?
显然你不能对int
自己做任何事情,即使是隐式转换int
也可以跟随标准转换。但我们可以(当然)让 SFINAE 承担责任:
struct A {
int i;
template<class T,std::enable_if_t<std::is_same_v<T,int>>* =nullptr>
operator T() const {return i;}
};
然后你可以写
f({A{1}});
(用户定义的文字会更简洁,但您说的是非常量表达式。)
这是否意味着答案是“是”或“否”取决于您,但我很确定没有其他方法可以在不允许标准转换的情况下使用大括号初始化器。
推荐阅读
- node.js - Nodemailer 和 ical-generator - 发送日历邀请
- c++ - 为什么在使用字符串时我的 for 循环不执行
- javascript - 我想使用 CSS 样式设置 JS 文件的样式,但出现错误
- java - 使用本地变量的单例安全发布
- c# - 为 UAT 项目 Web 窗体创建 Web 安装程序。、ASP.net、C#
- django - 启动 Django 项目
- python - 在 pandas 中组织单列以制作多列和数据框
- regex - 使用正则表达式解析文本文件
- sharepoint - 如何在 C# 中使用带有客户端 ID 和客户端密码的 SharePoint REST API 来获取网站集?
- django - 如何过滤所有子类别的查询集