首页 > 解决方案 > 转换构造函数和运算符都存在并且涉及显式性时的行为

问题描述

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

#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. 如果只有 operator 是显式的,则两种转换都使用构造函数。
  3. 如果只有构造函数是显式的,则第二个转换调用构造函数,第一个使用运算符。
  4. 如果两者都是显式的,我只能编译第二个表达式。它使用构造函数。

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

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

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

标签: c++implicit-conversionexplicitexplicit-conversion

解决方案


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

(强调我的)

1) 如果存在 from expressionto的隐式转换序列new_type,或者如果直接初始化对象或类型new_typefrom的引用的重载决议expression会找到至少一个可行的函数,则返回如同 by 初始化static_cast<new_type>(expression)的虚变量Tempnew_type Temp(expression);,这可能涉及隐式转换,对构造函数的new_type调用或对用户定义的转换运算符的调用。

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

对于第一种情况,您观察到的结果似乎与上述摘要略有不同,

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

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

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

为了回答您的问题,

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

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

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

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

另请注意,第一个表达式需要隐式转换,那么转换构造函数或转换运算符是否被标记为很explicit重要。另一方面,第二个表达式是显式转换,它不在乎。


推荐阅读