Непонятно как расставить объявления и реализации методов. C++

Есть хэдер:

#ifndef EMPLOYEES
#define EMPLOYEES

#include <memory>
#include <functional>
#include <sstream>
#include <string>

namespace employees {
struct Employee;
  
std::ostream & operator<<(std::ostream & out, const Employee & employ);
}

#endif

И сипипишник:

#include "employees.h"
#include <memory>
#include <sstream>
#include <string>
#include <functional>

namespace employees {
    struct Employee {
    private:
    public:
        std::string full_name;
        std::string full_name_tilda;
        int base_salary_usd_per_year;
        static std::unique_ptr<Employee> read_from(std::istream & in);
        explicit Employee(std::string name, int salary) : full_name(std::move(name)), base_salary_usd_per_year(salary) {
            for (char i : full_name) {
                if (i == ' ') {
                    full_name_tilda += '~';
                } else {
                    full_name_tilda += i;
                }
            }
        }
        virtual ~Employee() = default;
    };

    std::unique_ptr<Employee> Employee::read_from(std::istream & in) {
        std::string status, name;
        int salary{};
        in >> status >> name >> salary;
        if (status != "Employee") {
            return nullptr;
        }
        return std::make_unique<Employee>(name, salary);
    }

    [[nodiscard]] std::ostream & operator<<(std::ostream & out, const Employee & employ) {
        out << "Employee " << employ.full_name_tilda << " " << employ.base_salary_usd_per_year;
        return out;
    }
}

И майн:

#include "employees.h"
#include <sstream>
#include <string>
#include <type_traits>
#include "doctest.h"

std::string to_string(const employees::Employee &e) {
    std::stringstream s;
    static_cast<std::ostream &>(s) << e;
    return s.str();
}

std::unique_ptr<employees::Employee> from_string(const std::string &str) {
    std::stringstream s;
    s << str;
    return employees::Employee::read_from(static_cast<std::istream &>(s));
}

TEST_CASE("read_from empty") {
    CHECK(from_string("") == nullptr);
    CHECK(from_string("    ") == nullptr);
}

Ругается на эту строчку:

return employees::Employee::read_from(static_cast<std::istream &>(s));

incomplete type 'employees::Employee' named in nested name specifier Если я правильно понял, это значит, что Employee где-то используется перед его реализацией. Где именно, я найти не могу. Как исправить? P.S. read_from должен быть статическим - это принципиально.


Ответы (1 шт):

Автор решения: Harry

У вас есть вызов члена, о котором из предварительного объявления ничего не известно.

Внесите в заголовочный файл нормальное объявление:

namespace employees {

    struct Employee {
    public:
        std::string full_name;
        std::string full_name_tilda;
        int base_salary_usd_per_year;
        static std::unique_ptr<Employee> read_from(std::istream & in);
        explicit Employee(std::string name, int salary);
        virtual ~Employee() = default;
    };

    std::ostream & operator<<(std::ostream & out, const Employee & employ);
}

и тогда реализация будет:

namespace employees {

    Employee::Employee(std::string name, int salary)
        : full_name(std::move(name)), base_salary_usd_per_year(salary)
    {
        for (char i : full_name) {
            if (i == ' ') {
                full_name_tilda += '~';
            } else {
                full_name_tilda += i;
            }
        }
    }

        std::unique_ptr<Employee> Employee::read_from(std::istream & in) {
            std::string status, name;
            int salary{};
            in >> status >> name >> salary;
            if (status != "Employee") {
                return nullptr;
            }
            return std::make_unique<Employee>(name, salary);
        }

        [[nodiscard]] std::ostream & operator<<(std::ostream & out, 
                                                const Employee & employ) {
            out << "Employee " << employ.full_name_tilda 
                << " " << employ.base_salary_usd_per_year;
            return out;
        }
}

И все должно заработать...

→ Ссылка