Этот вопрос проще всего проиллюстрировать на примере, поэтому здесь идет речь:
(Не все реализации на самом деле компилируют его правильно, но мне интересно, если это ошибка.)
#include <algorithm>
class Picky
{
friend
Picky *std::copy<Picky const *, Picky *>(Picky const *, Picky const *, Picky *);
Picky &operator =(Picky const &) { return *this; }
public:
Picky() { }
};
int main()
{
Picky const a;
Picky b;
std::copy<Picky const *, Picky *>(&a, &a + 1, &b);
return 0;
}
std::copy
требуется выходной итератор ([gorithms.general] / p5); итераторы вывода, помимо прочего, требуют *r = o
быть действительным ([output.iterators], таблица 108), а не просто «иногда допустимо» или «допустимо в некоторых контекстах».
Так как для Picky *p, a;
, *p = a
не действует в большинстве случаев, Picky *
не является допустимым итератором вывода.
Хм, было бы здорово, если бы вы могли обобщить свой ответ на другие вещи
за конкретный пример, который я дал. Как, например,
std::vector::push_back(T const &)
или что угодно.
Подружиться с функцией-членом — абсолютное нет-нет, потому что вы даже не гарантированы, что есть функция-член с этой подписью ([member.functions] / p2, которую Стефан Т. Лававей называет «Исполнители STL могут быть хитрым правилом»):
Реализация может объявить дополнительную не виртуальную функцию-член
подписи внутри класса:
- путем добавления аргументов со значениями по умолчанию к сигнатуре функции-члена187 [Заметка: Реализация
не может добавлять аргументы со значениями по умолчанию для виртуальных, глобальных функций или функций, не являющихся членами. — конечная нота];- путем замены сигнатуры функции-члена значениями по умолчанию двумя или более сигнатурами функции-члена с эквивалентным поведением; а также
- добавив сигнатуру функции-члена для имени функции-члена.
187 Следовательно, адрес функции-члена класса в стандартной библиотеке C ++ имеет неопределенный тип.
Код может скомпилироваться, если std::copy()
не вызывает никаких других не дружественных функций, но мне еще не приходилось сталкиваться с такой реализацией. И нет никаких требований в стандартном ограничении, КАК std::copy()
достигается необходимый эффект.
Однако для этого требуется работающий и доступный оператор присваивания.