【问题标题】:Behavior when both conversion constructor and operator are present and explicitness is involved转换构造函数和运算符都存在且涉及显式性时的行为
【发布时间】:2019-08-06 10:23:21
【问题描述】:

我有一段代码,其中有转换构造函数和转换运算符。

#include <iostream>
struct ClassFloat;

struct ClassInt{
    int value;
    ClassInt(int c) : value(c){std::cout << "From integer\n";};
    ClassInt(ClassFloat x);
    //explicit ClassInt(ClassFloat x);
};

struct ClassFloat{
    float val;
    explicit operator ClassInt() {std::cout << "Conversion operator called\n"; return ClassInt{999};}
    //operator ClassInt() { std::cout << "Conversion operator called\n"; return ClassInt{999};}
};

ClassInt::ClassInt(ClassFloat x){
    std::cout << "Conversion constructor called!\n";
    value = (int)x.val;
}

int main(){
    ClassFloat floatObj{3.5f};
    ClassInt instance1 = floatObj;           // (1)
    ClassInt instance2 = (ClassInt)floatObj; // (2)
    return 1;
}
  1. 如果两者都是非显式的。我收到一个编译器错误,说第一个表达式不明确。第二个表达式调用构造函数。
  2. 如果只有运算符是显式的,则两种转换都使用构造函数。
  3. 如果只有构造函数是显式的,第二个转换调用构造函数,第一个使用运算符。
  4. 如果两者都是显式的,我只能编译第二个表达式。它使用构造函数。

我不明白为什么在第二个场景的第二个表达式中没有调用转换运算符。

我也期待在第四个场景中出现歧义错误(类似于第一个场景),但选择了构造函数。

我使用带有 -pedantic 和 -std=c++17 标志的 g++ 7.4.0 编译。

【问题讨论】:

    标签: c++ implicit-conversion explicit explicit-conversion


    【解决方案1】:

    首先c-style cast执行static_cast,然后

    (强调我的)

    1) 如果存在从expressionnew_type 的隐式转换序列,或者如果从expression 直接初始化对象或类型为new_type 的引用的重载决议将找到至少一个可行的函数, 然后static_cast&lt;new_type&gt;(expression)返回假想变量Temp,如同new_type Temp(expression);一样初始化,这可能涉及隐式转换,调用new_type的构造函数或调用用户定义的转换运算符。

    所以给定(ClassInt)floatObj;(初始化为ClassInt Temp(floatObj);),转换构造函数总是首选,它将直接用于构造ClassInt。虽然应用转换运算符需要从floatObjClassInt 的隐式转换(然后在概念上复制初始化临时ClassInt)。

    您观察到的结果似乎与上面的总结有些不同,对于第一种情况,

    1. 如果两者都是非显式的。我收到一个编译器错误,提示它不明确。

    只有第一个表达式会导致模棱两可的问题,第二个表达式会使用转换构造函数。

    顺便说一句:我尝试了gcc 7.3.0,结果符合预期。

    为了回答您的问题,

    我不明白为什么在第二个场景的第二个表达式中没有调用转换运算符。

    因为第二个表达式(c-ctyle cast)首选转换构造函数。

    我也期待在第四个场景中出现歧义错误(类似于第一个场景),但选择了构造函数。

    同上,第二个表达式优先使用转换构造函数;第一个表达式会导致错误,因为转换构造函数和转换运算符都标记为explicit

    还要注意第一个表达式需要隐式转换,那么转换构造函数或转换运算符是否标记为explicit 很重要。另一方面,第二个表达式是explicit conversion,它并不关心。

    【讨论】:

    • @Aconcagua 它只适用于第二个表达式(c-ctyle cast)。所以在第一种情况下,第一个表达式会导致歧义错误,第二个表达式将使用转换构造函数。
    • @Aconcagua 我最后加了解释,第4个场景的第一个表达式失败了,因为它需要隐式转换,但是转换构造函数和转换运算符都标记为explicit。现在清楚了吗?
    • 你是对的,在第一种情况下,只有第一个表达式会导致歧义(我之前没有注意到)
    • 但考虑到这一切,在我看来,即使在第一种情况、第一种表达方式中,更喜欢构造函数而不是转换更有意义......为什么标准委员会可能会做出不同的选择?
    • @Aconcagua 我不确定,是的,我同意在隐式转换场景和显式转换场景中表现不同是令人困惑的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2018-08-12
    • 2014-02-04
    • 2021-12-04
    • 2017-12-21
    • 2014-02-17
    • 1970-01-01
    相关资源
    最近更新 更多