首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >显式转换函数、直接初始化和转换构造函数

显式转换函数、直接初始化和转换构造函数
EN

Stack Overflow用户
提问于 2012-09-11 14:49:07
回答 2查看 1.6K关注 0票数 3

标准后的n3376草案例如(12.3.2:2)将显式转换函数转换为用户定义的类型:

代码语言:javascript
复制
class Y { };
struct Z {
  explicit operator Y() const;
};
void h(Z z) {
  Y y1(z); // OK: direct-initialization
}

根据12.3.2:2,显式转换函数“仅被视为用户定义的直接初始化转换”;然而,这似乎允许:

代码语言:javascript
复制
struct Y { Y(int); };
struct Z {
  explicit operator int() const;
};
void h(Z z) {
  Y y1(z); // direct-initialization
}

这似乎与标准的意图相冲突,确实遭到gcc-4.7.1的拒绝:

代码语言:javascript
复制
source.cpp: In function 'void h(Z)':
source.cpp:4:9: error: no matching function for call to 'Y::Y(Z&)'
source.cpp:4:9: note: candidates are:
source.cpp:1:12: note: Y::Y(int)
source.cpp:1:12: note:   no known conversion for argument 1 from 'Z' to 'int'
source.cpp:1:8: note: constexpr Y::Y(const Y&)
source.cpp:1:8: note:   no known conversion for argument 1 from 'Z' to 'const Y&'
source.cpp:1:8: note: constexpr Y::Y(Y&&)
source.cpp:1:8: note:   no known conversion for argument 1 from 'Z' to 'Y&&'

gcc拒绝将Z通过int转换为Y是正确的,还是标准确实允许这种使用?

我考虑了上述直接初始化的上下文;根据8.5:16中直接初始化到类类型的定义,调用构造函数时使用初始化表达式作为其参数,因此通过隐式转换序列(13.3.3.1)将其转换为参数类型。由于隐式转换序列是隐式转换(4:3),因此将复制初始化(8.5:14)建模,而不是直接初始化,所以12.3.2:2中的语言必须引用整个表达式。

还请注意,这并不违反12.3:4 (多个用户定义的转换);同一个编译器对删除explicit的相同代码感到高兴( Clang和Comeau也是如此):

代码语言:javascript
复制
struct Y { Y(int); };
struct Z { operator int(); };
void h(Z z) {
  Y y1(z); // direct-initialization
}

我认为杰西·古德在13.3.1.4:1中指出了operator Yoperator int两种情况的区别,但我仍然关注第三种情况:

代码语言:javascript
复制
struct X {};
struct Y { Y(const X &); };
struct Z {
  explicit operator X() const;
};
void h(Z z) {
  Y y1(z); // direct-initialization via class-type X
}

要绑定到X构造函数的单个const X &参数的临时Y的初始化按照13.3.1.4:1的直接初始化上下文进行,T作为XS作为Z。我认为这一条是不正确的,应改为:

13.3.1.4由用户-defined转换over.match.copy复制-初始化类 1-.当初始化要绑定到构造函数第一个参数的临时参数时,该构造函数将可能对cv限定的T的引用作为其第一个参数,在直接初始化类型为"cv2 T__“的对象的上下文中使用单个参数调用该参数时,还将考虑显式转换函数。..。

为避免混淆,我认为亦应修订12.3.2:2:

12.3.2转换函数class.conv.fct 2-转换函数可以是显式的(7.1.2),在这种情况下,它仅被视为在某些情况下(13.3.1.4、13.3.1.5、13.3.1.6)直接初始化(8.5)的用户定义的转换。..。

对以上各点有何评论?

EN

回答 2

Stack Overflow用户

发布于 2012-09-11 16:08:24

根据8.5和13.3.1.3,考虑了Y的构造函数,并通过过载分解选出了最优的构造函数。在这种情况下,相关的构造函数是Y(int);以及复制和移动构造函数。在过载解析过程中,13.3.2可行的函数over.match.viable指定如下:

第二,要使F成为一个可行的函数,每个参数都应该存在一个隐式转换序列(13.3.3.1),该序列将该参数转换为F的相应参数。..。

对于所有这些构造函数,不存在从ZintY风格之一的转换。为了说服我们自己,让我们研究一下标准对13.3.3.1隐式转换序列over.best.ics中的隐式转换序列的看法。

1隐式转换序列是用于将函数调用中的参数转换为被调用函数的相应参数类型的转换序列。转换序列是第4条中定义的隐式转换,这意味着它受对象初始化规则或单个表达式(8.5、8.5.3)引用的约束。

如果我们交叉引用第4条,那么我们就会了解到,隐式转换定义为复制初始化(即T t=e;,其中Tintez):

(§4.3)对于某些发明的临时变量t (8.5),表达式e可以隐式转换为T类型,当且仅当声明T t=e;格式良好时。..。

因此,我采用12.3.2:2不应用这个初始化,这发生在直接初始化的更大的上下文中。如果不这样做,将与最近的这一段相矛盾。

票数 4
EN

Stack Overflow用户

发布于 2012-09-11 18:12:22

我不是语言律师,但是标准的措辞对我来说意味着,将转换操作符标记为explicit需要明确指定转换类型(即int)作为对象y1初始化的一部分。使用代码Y y1(z),您似乎依赖于隐式转换,因为您为变量y1指定的类型是Y

因此,我期望在这种情况下正确使用显式转换运算符如下:

代码语言:javascript
复制
Y y1( int(z) ); 

或者,由于您实际上是在指定一个强制转换,最好是

代码语言:javascript
复制
Y y1( static_cast<int> (z) ); 
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12372442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档