C ++ добавление друга в шаблонный класс для Typecast

В настоящее время я читаю «Эффективный C ++», и есть глава, которая содержит код, похожий на этот:

template <typename T>
class Num {
public:
Num(int n) { ... }
};

template <typename T>
Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... }

Num<int> n = 5 * Num<int>(10);

В книге говорится, что это не сработает (и на самом деле не сработает), потому что вы не можете ожидать, что компилятор будет использовать неявное приведение типов для специализации шаблона.

В качестве решения предлагается использовать синтаксис «друг» для определения функции внутри класса.

//It works
template <typename T>
class Num {
public:
Num(int n) { ... }

friend
Num operator*(const Num& lhs, const Num& rhs) { ... }
};

Num<int> n = 5 * Num<int>(10);

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

Но почему я не могу получить тот же пример, работающий с общей функцией, а не с оператором?

template <typename T>
class Num {
public:
Num(int n) { ... }

friend
void doFoo(const Num& lhs) { ... }
};

doFoo(5);

На этот раз компилятор жалуется на то, что он вообще не может найти ‘doFoo’.
И если я объявляю doFoo вне класса, я получаю разумную ошибку несоответствующих типов. Похоже, часть «друг …» просто игнорируется.

Так есть ли проблемы с моим пониманием? В чем разница между функцией и оператором в этом случае?

8

Решение

Причина в том, что здесь

doFoo(5);

компилятор не может найти foo, учитывая int параметр. Это будет эквивалентно вызову вашего друга оператором, как это:

Num<int> n = 5 * 10;

Это будет «работать», но не вызывая friend operator* определены в вашем Num класс, но вызывая встроенный operator* для целых чисел, а затем с помощью неявного преобразования из NumКонвертирующий конструктор.

3

Другие решения

Основная проблема — поиск. friend Объявление обеспечивает объявление функции уровня пространства имен, но объявление доступно только внутри класса, который его поддерживает. В приведенном в книге примере это не является проблемой: функция принимает два аргумента вмещающего типа, при условии, что один из них относится к вмещающему типу, Argument Dependent Lookup будет искать внутри определения класса и находить оператор. В вашем случае это не так, поскольку существует один аргумент, и для этого требуется преобразование, компилятор не будет смотреть в определение класса.

Обратите внимание, что это независимо от шаблонов и конверсий:

class A {
friend void f( int ) {}
friend void g( int, A ) {}
};
int main() {
f(5);           // Error: lookup cannot find 'f' declared *only* inside A
g(5,A());       // Ok, one argument is 'A', lookup will find the function
}

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

class A {
friend void f() { std::cout << "inside A\n"; }
};
void f(int);     // only declaration
int main() {
f(5);         // "inside A"}

Это не может быть сделано для шаблона (и для всех создаваемых экземпляров типов), поскольку объявление друга — это объявление не шаблонной функции. Хотя вы можете поиграть с кодом только ради тестирования:

template <typename T>
struct Num {
Num(int x) ...
friend void f( Num const & );
};
Num<int> f(Num<int> const &);    // only declaration
int main() {
f(5);
}
1

Да, эти компиляторы кода не знают, как с ним работать.
лайк
doFoo (5)

компилятор не знает 5 это int

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector