【问题标题】:When are user-defined conversion sequences not considered for selecting viable constructors in C++?何时不考虑在 C++ 中选择可行的构造函数时不考虑用户定义的转换序列?
【发布时间】:2016-04-28 09:38:11
【问题描述】:

我在C++标准草案N4582中看到了如下的文字:

[over.best.ics/4] 但是,如果目标是

(4.1) 构造函数的第一个参数或

(4.2) 自定义转换函数的隐式对象参数

而构造函数或用户定义的转换函数是候选者

(4.3) 13.3.1.3,当参数是类复制初始化第二步中的临时参数时,或

(4.4) 13.3.1.4、13.3.1.5 或 13.3.1.6(在所有情况下),

不考虑用户定义的转换序列。

我对粗体部分感到困惑,不知道如何理解它。我编写了以下程序:

#include <iostream>
using namespace std;    
struct A {
    A(int) {}
    operator int() {cout << "user-defined conversion" << endl; return 0;}
    A(A&) {} //prevent default copy
};
int main()
{
    A a = A(0);
}

在g++ 5.3.0下运行良好,输出“user-defined conversion”,表示发生了用户定义的转换。当然,也可以理解为临时的A(0)不是copy-initialization的结果。接下来我将程序更改为:

#include <iostream>
using namespace std;    
struct A {
    A(int) {}
    operator int() {cout << "user-defined conversion" << endl; return 0;}
    A(A&) {} //prevent default copy
};
A foo() {return A(0);}
int main()
{
    A a = foo();
}

现在 foo() 的值是从 A(0) 初始化的临时副本,但程序仍然有效。为什么会这样?

【问题讨论】:

  • 您的报价不正确;您省略了 4.2 并将 4.3 重新编号为 4.2。
  • 你明白“第二步”指的是什么吗?
  • @ecatmur 抱歉引用不正确。
  • @T.C.不,我不太明白“第二步”的含义。

标签: c++ standards implicit-conversion


【解决方案1】:

您可以阅读[dcl.init]/17 了解实际的标准语。这里的“第二步”是指从不相关类型的b 复制初始化类类型A 的变量。在这种情况下,复制初始化分两步进行:

  • 第 1 步:将b 隐式转换为A。如果为此调用转换构造函数,它会创建一个临时的A
  • 第 2 步:然后根据转换结果初始化 A 变量。 (在理智的课程中,这通常会被省略。)

那句话的意思是,您在第二步中不进行用户定义的转换。

例如,使用您的AA a = 0;。在第一步中,您从0 临时创建一个A。在第二步中,您尝试使用该临时值初始化 a - 不使用用户定义的转换。那失败了,因为 A 构造函数都不可行。

【讨论】:

  • 而第二步不做用户自定义转换的理由是你不要在一个单一的转换序列中做两次用户自定义的转换。
  • @MSalters 那么,如果它无论如何都不起作用,为什么要明确禁止它呢?
  • @Barry:绝对可以;只是编译器需要 some 限制。目前,如果单个 UDC 不足,编译器可以放弃。如果将限制设置为 2,则需要检查所有可能的对。如果将限制设置为 3,编译器必须检查所有三元组。复杂性显然是单个序列中允许的 UDC 数量的指数。请记住,特定的 UDC 可能是模板化的,因此需要实例化,因此即使是单级检查也很昂贵。
【解决方案2】:

只有 2 个 ctor,一个引用现有对象(非临时对象),另一个接受 int。

您的代码产生(带有附加消息):

int ctor
user-defined conversion
int ctor
user-defined conversion
int ctor

首先是foo里面的构造。

第二个是由于你阻止了返回值不能通过复制构造,所以编译器将构造的值转换为int

第三个是因为它使用接受int 的ctor 来构建返回值。

第四个是(和第二个一样)由于返回值不能用于构造a,所以将其转换为int

第五个是因为它使用带有int的ctor来构建a

【讨论】:

    猜你喜欢
    • 2019-04-03
    • 2019-02-03
    • 2016-05-25
    • 2019-08-26
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    相关资源
    最近更新 更多