Почему универсальный тип, который может быть приведен, не конвертируется неявно? - PullRequest
0 голосов
/ 22 декабря 2018

У меня есть класс A и класс B, оба являются общими с параметром типа T.Объект A<T> может быть приведен к B<T>.У меня есть универсальная перегрузка оператора на B, которую я хочу иметь возможность вызывать для объекта A и B объекта, где объект A неявно преобразуется.

Когда я пытаюсьэто не компилируется:

template <typename T>
class A {};

template <typename T>
class B {
public:
    B() {}
    B(const A<T> &a) {}
};

template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
    return B<T>(); // doesn't matter
}

int main() {
    A<int> objA;
    B<int> objB;

    B<int> combined1 = objA * objB; // error: operator* isn't defined on these types
    B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine

    return 0;
}

Однако, когда A и B не являются универсальными, все работает нормально:

class A {};

class B {
public:
    B() {}
    B(const A &a) {}
};

B operator*(const B &obj1, const B &obj2) {
    return B(); // doesn't matter
}

int main() {
    A objA;
    B objB;

    B combined1 = objA * objB; // fine
    B combined2 = static_cast<B>(objA) * objB; // also fine

    return 0;
}

Почему это так?Есть ли что-то в создании универсальной перегрузки оператора, которая означает, что тип не может быть выведен?

Ответы [ 3 ]

0 голосов
/ 22 декабря 2018

Вы можете определить функцию друга в class A, которая вызывает функцию вашего шаблона

template <class T>
class B;

template <typename T>
class A {
    friend B<T> operator*(const B<T> &obj1, const B<T> &obj2) {} # here call template function
};

template <typename T>
class B {
public:
    B() {}
    B(const A<T> &a) {}

};

template <typename T>
B<T> operator*(const B<T> &obj1, const B<T> &obj2) {
    return B<T>(); // doesn't matter
}

int main() {
    A<int> objA;
    B<int> objB;

    B<int> combined1 = objA * objB; // fine
    B<int> combined2 = static_cast<B<int>>(objA) * objB; // fine

    return 0;
}
0 голосов
/ 22 декабря 2018

Во время вывода аргумента преобразование / повышение не происходит, поэтому для

objA * objB

При проверке достоверности перегрузки кандидатов невозможно вывести T для:

template <typename T> B<T> operator*(const B<T> &, const B<T> &);

Таким образом, эта перегрузка отклоняется.

Один из способов исправить это создать не шаблонную функцию.Asit должен применяться к шаблону classe, один из способов сделать это с помощью friend функций:

template <typename T>
class B {
public:
    B() {}
    B(const A<T>&) {}

    friend B operator*(const B&, const B&) { return /*...*/; }
};

Теперь objA * objB учитывает перегрузку B<int> operator*(const B<int>&, const B<int>&), и может произойти преобразование, чтобы увидеть, является ли функция жизнеспособной (иэто так).

Демо

0 голосов
/ 22 декабря 2018

Вообще, неявные преобразования не допускаются при выводе аргументов, я могу думать о , выведенном из базы , как о допустимом.В выражении

B<int> combined1 =  objA * objB;

предполагается, что найдены жизнеспособные перегрузки для objA * objB, в том числе найденные ADL. Возможны следующие варианты:

template <typename T>
B<T> operator*(const A<T> &obj1, const B<T> &obj2) {...}

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

 B<int> combined1 = operator*<int>(objA, objB);

Но я бы не стал этого делать, придерживайтесь актерского состава, лучше объясните намерения.

...