Ну начнём с того, что добавив static в объявление сэта мы не просто "заствили программу компилироваться". Мы напрочь поменяли смысл этого сэта. Как только мы сделали сэт статическим, он стал общим для всех инстансов класса AutoPost. Я очень сомневаюсь, что мы хотели этого добиться.
Далее, как бороться с ошибкой компиляции, которая выскакивает, если мы убираем ключевое слово static из объявления любого из сэтов. Дело в том, что мы задекларировали метод-геттер (для примера возьмём getManagerSet), как константный (const в конце). Что это обозначает? Это обозначает, что метод не имеет право менять поля своего объекта. Если рассмотреть чуть глубже, как подобный запрет реализован на уровне типов языка, то мы поймём, что в константном методе this имеет тип
const AutoPost* const (константный указатель на константные данные), в то время как в обычном методе он имеет тип
AutoPost* const (константный указатель на неконстантные данные). Из этого следует, что в константном методе все поля класса, так же являются константными (так как доступ к ним производится, явно или неявно, через this, а последний константен). Таким образом, становится понятно почему компилятор ругается - мы пытаемся константный сэт вернуть по неконстантной ссылке наружу, где его смогут поменять, что нарушит правило константного метода.
На самом деле, это всё - лишь вершина айсберга. Если мы изменим сигнатуру геттера на такую:
Код: Выделить всё
const set<Manager>& AutoShop::getManagerSet() const
То у нас скомпилируется в этом месте, но перестанет компилироваться в другом. Квалификатор const придётся добавить ещё и в параметр метода add. А после очередного запуска компиляции мы наконец-то увидим ту ошибку, которую побороть уже не сможем. А именно, компилятор скажет, что не может вызывать неконстантный метод insert у константного сэта.
К чему я это всё клоню? К тому, что идея делать геттер getManagerSet константным была в корне не верна с самого начала. Константный метод предусматривает запрет на модификацию состояния объекта, при чём не только явную, но и неявную (через возврат ссылок или указателей и последующей модификации по ним). Мы же наш геттер используем как раз для того, чтобы менять сэт. Это как раз наша цель! Таким образом мы пришли к противоречию.
Предлагаю полностью пересмотреть дизайн класса. Первое, что мы можем сделать - это убрать const из объвления геттеров для сэтов. И это обосновано. Мы хотим менять эти сэты. Далее возникает вопрос, а зачем нам вообще нужны геттеры и зачем нам вообще нужен template метод add? Ведь изначальный вариант, когда было три функции addManager, addClient и addAutoConfiguration не только содержал меньше кода в целом, но и был более правильным с точки зрения инкапсуляции (у нас не было трёх геттеров, которые может дёргать кто угодно извне и менять наши сэты, даже если мы этого не хотим). С другой стороны, если template метод - это обязательно требование (предположим такое требование было сделано начальником или преподавателем - не суть важно кем именно), то в любом случае есть более изящное решение, а именно сделать специализацию template метода add для трёх этих типов. В таком случае от геттеров, нарушающих инкапсуляцию, также можно будет избавиться.