最小示例程序:
#include <vector>
void f(std::vector<int>) {} // #1
void f(std::vector<void *>) {} // #2
int main() { f({ 1 }); }
从直觉上来说,这是一个有效的程序:使用重载#1的调用将是有效的,使用重载#2的调用将格式不正确,因此应选择重载#1。这就是c所做的。
不幸的是,按照标准,这似乎是模棱两可的,因为存在std::vector<void *>
的构造函数,可以通过将其隐式转换为int
来与size_t
一起调用。在重载解析期间应该忽略构造函数为explicit
的事实,如果选择了该重载,则程序将很容易变形。 GCC拒绝了电话通话的模棱两可,看来这样做是正确的。
我可以通过拼写类型名称f(std::vector<int>{ 1 });
来修改代码,以使GCC接受呼叫。我还可以使用带有默认参数的标签调度,以允许显式指定要使用的重载,同时允许像以前一样接受现有的调用。
这两个都是可以接受的,但是当回到真实代码时,它们很快就会变得很冗长。还有另一种选择可以让我避免拼写完整的类型名称,而是坚持使用当前的重载吗?我想了一会儿{ 1, }
可以工作,但是当然不行,int i = { 1, };
也是完全有效的,不能用来避免#2。
如果有助于排除某些替代方法,则实际代码确实涉及std::vector<int>
和std::vector<T>
,并且确实涉及到带有大括号的初始化程序列表的调用,该列表包含单个整数表达式,但是T
是用户定义的类型,而不是内置类型,并且表达式不是常量值。
“否”是可以接受的答案,但是在这种情况下,请详细说明,请表明没有这种选择。
答案 0 :(得分:0)
总是很难证明它是负面的,但考虑到引入的可能性
using I=std::vector<int>;
我认为您是在问“有没有一种方法可以避免标准转换为size_type
来消除竞争中的其他重载”?
很显然,您无法对int
本身做任何事情,即使隐式转换为int
也可以进行标准转换。但是我们可以(当然)bring SFINAE to bear:
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}});
(用户定义的文字会简短一些,但您说的是非常量表达式。)
由您决定是否回答是完全由您决定,但是我很确定没有允许标准转换的使用花括号初始化器的其他方法。