uwe*_*sky 21 c++ gcc clang language-lawyer
在下面的代码中,clang和EDG诊断出一个模糊的函数调用,而gcc和Visual Studio接受代码.
struct s
{
typedef void(*F)();
operator F(); //#1
operator F() const; //#2
};
void test(s& p)
{
p(); //ambiguous function call with clang/EDG; gcc/VS call #1
}
Run Code Online (Sandbox Code Playgroud)
根据C++标准草案(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf)第13.3.1.1.2节说2;
具有唯一名称call-function并具有R call-function形式的代理调用函数(conversion-type-id F,P1 a1,...,Pn an){return F(a1,...,an); }也被视为候选函数.
在上面的代码中,似乎意味着正在考虑两个调用函数定义(每个转换函数一个),但两个调用函数具有相同的签名(因此模糊性),因为转换运算符的cv限定符似乎不是在呼叫功能签名中考虑到了.
我希望用gcc和Visual Studio调用#1.因此,如果clang/EDG正确拒绝上述代码,那么有人可以说明为什么标准规定在这种情况下应该存在歧义以及哪些代码受益于代理呼叫功能的属性的原因?谁是对的:clang(3.5)/ EDG(310)或gcc(4.8.2)/ VS(2013)?
Clang和EDG是对的.
这是如何工作的.标准说(与你的报价相同的来源):
另外,对于
T表单中声明的每个非显式转换函数Run Code Online (Sandbox Code Playgroud)operator conversion-type-id () attribute-specifier-seq[opt] cv-qualifier ;其中[在您的示例中满足各种条件],具有唯一名称call-function并具有表单的代理调用函数
Run Code Online (Sandbox Code Playgroud)R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1, ... ,an); }也被认为是候选函数.[对继承的转换也这样做] ^ 128
脚注指出,这可能会产生多个具有无法区分签名的代理人,如果这些代理人没有被明显更好的候选人所取代,那么这种呼吁就是含糊不清的.
遵循此方案,您的类型有两个转换运算符,产生两个代理:
// for operator F();
void call-function-1(void (*F)()) { return F(); }
// for operator F() const;
void call-function-2(void (*F)()) { return F(); }
Run Code Online (Sandbox Code Playgroud)
您的示例不包含任何其他候选人.
然后编译器执行重载决策.因为两个调用函数的签名是相同的,所以它们将使用相同的转换序列 - 特别是,它将在两种情况下使用转换函数的非const重载!因此无法区分这两个函数,并且调用是模糊的.
理解这一点的关键是,将对象传递给代理项时实际使用的转换不必使用代理生成的转换函数!
我可以看到GCC和MSVC可能会在这里找到错误答案的两种方式.
选项1是他们看到两个具有相同签名的代理人,并以某种方式将它们合并为一个.
选项2,更有可能的是,他们认为,"嘿,我们不需要在这里进行昂贵的对象转换搜索,我们已经知道它将使用代理生成的转换函数".这似乎是一种声音优化,除了在这种边缘情况下,这种假设是错误的.无论如何,通过将转换绑定到源转换函数,其中一个代理使用identity-user-identity作为对象的转换序列,而另一个使用const-user-identity,使其更糟.
| 归档时间: |
|
| 查看次数: |
705 次 |
| 最近记录: |