C ++: пользовательская ошибка явного преобразования типа - PullRequest
0 голосов
/ 05 февраля 2020

Вот как выглядит код:

using namespace std;
class dummy{
public:
    int x;
    explicit dummy(int x = 0) : x{ this->x = x } {}; //explicit has no effect here
};

class myClass {
public:
    operator int(); //<---problematic conversion
    explicit operator dummy();

};

myClass::operator int() {
    return 10;
}

myClass::operator dummy(){
    return dummy(9);
}

int main() {
    myClass mc1; 
    dummy val = (dummy)mc1;
    cout << "mc1 int cast: " << mc1 << endl; 
    cout << "val.x: :" << val.x << endl;
    std::cin.get();
    return 0;
}

Я использую компилятор ms vs и получаю c2440 (ошибка приведения типа). Насколько я понимаю, я не делаю ничего плохого в синтаксисе. Проблема в том, что он работает нормально, если я удаляю неявное преобразование: operator int() и его соответствующую функцию из кода. ie:

using namespace std;
class dummy{
public:
    int x;
    explicit dummy(int x = 0) : x{ this->x = x } {}; //explicit has no effect here
};

class myClass {
public:
    //operator int();
    explicit operator dummy();

};
/*
myClass::operator int() {
    return 10;
}*/

myClass::operator dummy(){
    return dummy(9);
}

int main() {
    myClass mc1; 
    dummy val = (dummy)mc1;
    //cout << "mc1 int cast: " << mc1 << endl; 
    cout << "val.x: " << val.x << endl;
    std::cin.get();
    return 0;
}

это приведет к следующему выводу (как и ожидалось):

val.x: 9

Редактировать: явное ключевое слово отсутствовало во втором примере. Выход такой же

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

Компилируя ваш исходный код с помощью g cc -9 в Ubuntu 18.04, я получаю следующее:

test.cpp:27:24: error: call of overloaded ‘dummy(myClass&)’ is ambiguous
   27 |     dummy val = (dummy)mc1;
      |                        ^~~
test.cpp:7:14: note: candidate: ‘dummy::dummy(int)’
    7 |     explicit dummy(int x = 0) : x{ this->x = x } {}; //explicit has no effect here
      |              ^~~~~
test.cpp:4:7: note: candidate: ‘constexpr dummy::dummy(const dummy&)’
    4 | class dummy{
      |       ^~~~~
test.cpp:4:7: note: candidate: ‘constexpr dummy::dummy(dummy&&)’

Что происходит, компилятор не может сказать, хотите ли вы создать новый класс 'dummy' из преобразования int в 'myClass' или в новый 'dummy' из неявно сгенерированного оператора копирования 'dummy'.

Это вызывает al oop, где myClass можно преобразовать в оба значения int и dummy, что означает, что компилятор застревает, пытаясь преобразовать «myClass», поскольку он не знает, что вы на самом деле хотите сделать - преобразовать в «пустышку», преобразовать в «пустышку», затем скопировать или создать новую «пустышку» с помощью преобразование 'myClass' в int

Решением этого является сделать ваш оператор преобразования в int explicit, это предотвращает неявное преобразование компилятором и позволяет этому работать (по крайней мере, на g cc - 9).

Это обновленная копия вашего кода, которая будет работать:

using namespace std;
class dummy{
public:
    int x;
    explicit dummy(int x=0) : x(x) {}


};

class myClass {
public:
    explicit operator int(); // < Set to explicit
    explicit operator dummy();

};

myClass::operator int() {
    return 10;
}

myClass::operator dummy(){
    return dummy(9);
}

int main() {
    myClass mc1; 
    dummy val = static_cast<dummy>(mc1);
    cout << "mc1 int cast: " << static_cast<int>(mc1) << endl; 
    cout << "val.x: :" << val.x << endl;
    std::cin.get();
    return 0;
}

Это компилируется с g cc -9 и clang ++ - 9

В качестве примечания пожалуйста, пожалуйста, пожалуйста, никогда не используйте C приведения в стиле C ++, они подвержены ошибкам и боль в заднице для отладки

2 голосов
/ 05 февраля 2020

Существует неоднозначность между способом создания объекта типа dummy.

Первый - когда вызывается operator dummy, создающий временный объект типа dummy и затем вызывается конструктор копирования из-за явного преобразования приведения.

Второй - когда объект типа myClass преобразуется в тип int из-за operator int, а затем выполняется преобразование конструктор класса myClass вызывается для создания объекта типа dummy.

Вот демонстрационная программа, которая показывает два способа создания объекта класса с использованием явного приведения.

#include <iostream>

struct A
{
    explicit A( int x = 0 ) : x( x ) { std::cout << "A( " << x << " )\n"; }
    A( const A & ) { std::cout << "A( const A & )\n"; }
    int x;
};

int main() 
{
    A a( 1 );

    std::cout << '\n';

    ( A )a;

    std::cout << '\n';

    ( A )2;


    return 0;
}

Вывод программы:

A( 1 )

A( const A & )

A( 2 )

По сравнению с вашей программой в вашей программе есть еще один шаг перед использованием этих способов: любой объект типа myClass будет предварительным преобразуется в тип dummy или в тип int.

...