- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
在以下代码中,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
}
根据 C++ 标准草案 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf) 第 13.3.1.1.2 节 2 说;
a surrogate call function with the unique name call-function and having the form R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); } is also considered as a candidate function.
在上面的代码中,这似乎意味着正在考虑两个调用函数定义(每个转换函数一个),但是两个调用函数具有相同的签名(因此存在歧义),因为转换运算符的 cv 限定符不似乎在调用函数签名中考虑到了。
我希望 #1 会像 gcc 和 Visual Studio 一样被调用。因此,如果 clang/EDG 拒绝上述代码是正确的,有人可以解释一下为什么标准规定在这种情况下应该有歧义以及 代码从代理调用函数的属性中受益?谁是对的:clang(3.5)/EDG(310) 还是 gcc (4.8.2)/VS(2013)?
最佳答案
Clang 和 EDG 是对的。
这是它的工作原理。该标准说(与您的报价相同的来源):
In addition, for each non-explicit conversion function declared in
T
of the formoperator conversion-type-id () attribute-specifier-seq[opt] cv-qualifier ;
where [various conditions fulfilled in your example], a surrogate call function with the unique name call-function and having the form
R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1, ... ,an); }
is also considered as a candidate function. [do the same for inherited conversions]^128
脚注指出,这可能会产生多个具有无法区分签名的代理,如果这些代理没有被明显更好的候选者取代,则该调用是模棱两可的。
按照这个方案,你的类型有两个转换运算符,产生两个代理:
// for operator F();
void call-function-1(void (*F)()) { return F(); }
// for operator F() const;
void call-function-2(void (*F)()) { return F(); }
您的示例不包含任何其他候选人。
然后编译器执行重载决议。因为这两个调用函数的签名是相同的,所以它将对两者使用相同的转换序列 - 特别是,它将使用转换函数的非常量重载在这两种情况下!所以无法区分这两个函数,调用有歧义。
理解这一点的关键是,在将对象传递给代理项时实际使用的转换不必使用为代理项生成的转换函数!
我可以看到 GCC 和 MSVC 在这里得出错误答案的两种方式。
选项 1 是他们看到两个具有相同签名的代理,然后以某种方式将它们融合为一个。
选项 2 更有可能是他们认为,“嘿,我们不需要在这里为对象进行昂贵的转换搜索,我们已经知道它将使用生成代理的转换函数为了”。这听起来像是一种优化,除了在这种极端情况下,这种假设是错误的。无论如何,通过将转换绑定(bind)到源转换函数,其中一个代理使用 identity-user-identity 作为对象的转换顺序,而另一个使用 const-user-identity,使情况变得更糟。
关于c++ - C++ 中代理调用函数的意外歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22258831/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!