почему код с template<class T> компилируется, а без него нет
#include <iostream>
using namespace std;
struct a
{
friend void operator+(const a&, int)
{
cout << "ddd";
}
} A;
template <class T>
struct c
{
operator a&() const noexcept
{
return A;
}
operator a() const noexcept
{
return A;
}
};
int main()
{
c<a> C{};
C + 1;
return 0;
}
Если функция объявлена только как friend внутри класса, то она формально принадлежит охватывающему пространству имен. Но при этом она не видна обычному процессу поиска имен, а может быть видна лишь ADL-поиску (Argument Dependent Lookup).
ADL-поиск делается через ассоциированные пространства имен и ассоциированные классы. Если один из аргументов имеет тип специализированного шаблона, то в список ассоциированных классов будут добавлены все типы аргументов этого шаблона.
В вашем примере поиск подходящего оператора + производится в глобальном пространстве имен. Один из аргументов + является специализацией шаблона c с аргументом a. Это приводит к включению a в список ассоциированных классов и к тому, что friend-функции этого класса становится видимыми с точки зрения ADL в глобальном пространстве имен.
Если вы уберете шаблонность, то класс a будет совершенно посторонним классом, никак не фигурирующим в выражении C + 1. Он не будет рассматриваться ADL в качестве ассоциированного класса и его friend-функции так и останутся "невидимыми".
Если вы дополнительно явно объявите свой оператор в охватывающем пространстве имен
struct a
{
friend void operator+(const a&, int)
{
cout << "ddd";
}
} A;
void operator+(const a&, int);
тот он будет виден сразу и всегда обычному процессу поиска имен. Зависимость от ADL (и от шаблонности) сразу исчезнет и код будет компилироваться.
Продвижение своими сайтами как стратегия роста и независимости