I am solving a task on "producer and consumer" multithreading model. In consumer class I am trying to make a method that would get private buffer from producer object using "friend", but somewhy the code doesn't compile: 'units' is a private member of'p_c_model::Producer'. Spent a lot of time trying to fix it, but didn't succeed. Even signed up here. Please, help me fix this. Thank you in advance!
//Buffer.h
#ifndef TASK03_196_TATARINOV_23_BUFFER_H
#define TASK03_196_TATARINOV_23_BUFFER_H
#include <stack>
#include <mutex>
#include <condition_variable>
///Представляет модель "производитель и потребитель".
namespace p_c_model {
    ///Представляет собой класс для обмена данными между
    ///производителями и потребителями.
    template<class T>
    class Buffer {
    private:
        ///Максимальное количество элементов в буфере.
        static const size_t st_max_size = 10000;
        ///Контейнер для хранения элементов буфера.
        std::stack<T> st;
        std::mutex mu;
        std::condition_variable cond;
    public:
        ///Добавляет новый элемент в буфер.
        void add(const T& newElement);
        ///Удалаяет верхний элемент из буфера.
        T remove();
        ///Возвращает true, если буфер пуст.
        bool empty();
    };
}
#endif //TASK03_196_TATARINOV_23_BUFFER_H
//Buffer.cpp
#include "Buffer.h"
namespace p_c_model{
    template<class T>
    void Buffer<T>::add(const T& newElement) {
        while (true) {
            std::unique_lock<std::mutex> locker(mu);
            cond.wait(locker, [this](){ return st.size() < st_max_size; });
            st.push(newElement);
            locker.unlock();
            cond.notify_all();
            return;
        }
    }
    template<class T>
    T Buffer<T>::remove(){
        while (true)
        {
            std::unique_lock<std::mutex> locker(mu);
            cond.wait(locker, [this](){ return !st.empty(); });
            T  top = st.top();
            st.pop();
            locker.unlock();
            cond.notify_all();
            return top;
        }
    }
    template<class T>
    bool Buffer<T>::empty(){
        return st.empty();
    }
}
//Producer.h
#ifndef TASK03_196_TATARINOV_23_PRODUCER_H
#define TASK03_196_TATARINOV_23_PRODUCER_H
#include <fstream>
#include "Buffer.h"
#include "Consumer.h"
namespace p_c_model{
    class Producer{
    private:
        Buffer<std::string> units;
        Buffer<unsigned int> prices;
        std::ifstream fin;
        std::mutex mu;
        friend template class<T>
        void Consumer<T>::get_buffer(Producer& pr);
    public:
        explicit Producer(const std::string& path);
        ~Producer();
        void run();
    };
}
#endif //TASK03_196_TATARINOV_23_PRODUCER_H
//Producer.cpp
#include <iostream>
#include <thread>
#include "Producer.h"
namespace p_c_model{
    Producer::Producer(const std::string& path){
        fin.open(path);
    }
    Producer::~Producer() {
        fin.close();
    }
    void Producer::run() {
        std::string unit;
        unsigned int price;
        while(!fin.eof()){
            fin >> unit >> price;
            units.add(unit);
            prices.add(price);
            {
                std::unique_lock<std::mutex> locker(mu);
                std::cout << "Unit \"" << unit << "\" of price " << price <<
                          "is taken out of the warehouse\n";
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    }
}
//Consumer.h
#ifndef TASK03_196_TATARINOV_23_CONSUMER_H
#define TASK03_196_TATARINOV_23_CONSUMER_H
#include <fstream>
#include "Buffer.h"
#include "Producer.h"
namespace p_c_model{
    class Producer;
    template<class T>
    class Consumer{
    private:
        Buffer<T>& objects;
        std::ofstream fout;
        std::mutex mu;
        unsigned long long overall_price;
    public:
        explicit Consumer(const std::string& path);
        ~Consumer();
        void run();
        void get_buffer(Producer& pr);
    };
}
#endif //TASK03_196_TATARINOV_23_CONSUMER_H
//Consumer.cpp
#include <iostream>
#include <thread>
#include "Producer.h"
#include "Consumer.h"
namespace p_c_model{
    template<class T>
    Consumer<T>::Consumer(const std::string& path) : overall_price(0){
        fout.open(path);
    }
    template<class T>
    Consumer<T>::~Consumer() {
        fout.close();
        std::cout << "Overall price is " << overall_price;
        fout << "Overall price is " << overall_price;
    }
    template<class T>
    void Consumer<T>::run() {
        if(typeid(T) == typeid(std::string)) {
            while (!objects.empty()) {
                T unit = objects.remove();
                fout << unit;
                {
                    std::unique_lock<std::mutex> locker(mu);
                    std::cout << "Unit \"" << unit << "\" is entrained in the truck\n";
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        } else if (typeid(T) == typeid(unsigned int)){
            while (!objects.empty()) {
                T unit = objects.remove();
                fout << unit;
                overall_price += *reinterpret_cast<unsigned long long *>(&unit);
                {
                    std::unique_lock<std::mutex> locker(mu);
                    std::cout << "+" << unit << " in price list\n";
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        }
    }
    template<class T>
    void Consumer<T>::get_buffer(Producer &pr) {
        if(typeid(T) == typeid(std::string)){
            objects = pr.units;
        } else if (typeid(T) == typeid(unsigned int)){
            objects = pr.prices;
        }
    }
}
