最小示例程序:
#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
它是用户定义的类型,而不是内置类型,并且表达式是不是一个常数值。
“否”是可以接受的答案,但在这种情况下,请详细说明,请表明没有这样的选项。