lapots
lapots

Reputation: 13395

multiple errors undefined reference to method

I have such header file declaration

#ifndef CONTAINER_H
#define CONTAINER_H

#include <map>
#include "object.h"

namespace memory {

template<class T>
class Collector {
};

template <class T>
class Collector<T*> {

private:
    std::map<std::string, T*> mem_storage;
public:
    std::string put_object(T* to_store);
    T* get_object(std::string key);
    void list_objects();
    void clean_up();
    void clean_object(std::string key); // force cleaning
    void mark_object_to_remove(std::string key); // mark unused
    void clean_removable(); // move to scheduled task

    ~Collector() {};
};

}

#endif

And such implementation

#include "../headers/container.h"

#define null nullptr

#include <iostream>
#include <string>

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>

using namespace memory;

template<typename T>
void Collector<T*>::clean_object(std::string key) {
    int removed = mem_storage.erase(key);
    std::string removed_string = boost::lexical_cast<std::string>(removed);
}

template<typename T>
void Collector<T*>::clean_up() {
    mem_storage.clear();
}

template<typename T>
T* Collector<T*>::get_object(std::string key) {
    typename std::map<std::string, T*>::iterator it = mem_storage.find(key);
    if (it != mem_storage.end()) {
        return it->second;
    } else {
        return null;
    }
}

template<typename T>
void Collector<T*>::list_objects() {
    for (typename std::map<std::string, T*>::iterator it = mem_storage.begin(); it != mem_storage.end(); ++it) {
        std::cout << it->first << " => " << it->second->to_string() << std::endl;
    }
}

template<typename T>
std::string Collector<T*>::put_object(T* to_store) {
    boost::uuids::uuid uuid = boost::uuids::random_generator()();
    std::string key = boost::uuids::to_string(uuid);
    mem_storage[key] = to_store;
    return key;
}

template<typename T>
void Collector<T*>::mark_object_to_remove(std::string key) {
    mem_storage.find(key)->second->removable = true;
}

template<typename T>
void Collector<T*>::clean_removable() {
    typename std::map<std::string, T*>::iterator it = mem_storage.begin();
    while (it != mem_storage.end()) {
        std::string id = it->first;
        T instance = it->second;
        if (instance->removable) {
            mem_storage.erase(it++);
        } else {
            ++it;
        }
    }
}

My main file looks like this

#include <iostream>

#define byte unsigned char
#define null nullptr

#include "base/headers/object.h"
#include "base/headers/indexed_object.h"
#include "base/headers/container.h"
#include "base/headers/reflector.h"

void garbage_collection_prototype_example() {
    core::Object *io = runtime::RuntimeReflector::create_instance(
        "core::IndexedObject");
    core::Object *io_new = runtime::RuntimeReflector::create_instance("core::IndexedObject");
    std::cout << "Class 1 name: [" + io->get_class_name() + "]" << std::endl;
    std::cout << "Class 2 name: [" + io_new->get_class_name() + "]" << std::endl;

    bool is_same = io_new->is_same_instance(io);
    std::cout << "Is same: " << std::boolalpha << is_same << std::endl;

    memory::Collector<core::Object*> *garbage_collector = new memory::Collector<core::Object*>();
    std::string key = garbage_collector->put_object(io);
    std::string key_new = garbage_collector->put_object(io_new);
    garbage_collector->list_objects();

    garbage_collector->mark_object_to_remove(key);
    garbage_collector->clean_removable();

    garbage_collector->list_objects();

    garbage_collector->clean_up();
}

int main(int argc, char *argv[]) {
    garbage_collection_prototype_example();
    return 0;
}

But I have bunch of errors when I try to build project

D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:22: undefined reference to `memory::Collector<core::Object*>::put_object(core::Object*)'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:23: undefined reference to `memory::Collector<core::Object*>::put_object(core::Object*)'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:24: undefined reference to `memory::Collector<core::Object*>::list_objects()'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:26: undefined reference to `memory::Collector<core::Object*>::mark_object_to_remove(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:27: undefined reference to `memory::Collector<core::Object*>::clean_removable()'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:29: undefined reference to `memory::Collector<core::Object*>::list_objects()'
D:\c++\eclipse_workspace\SDLAttempts\Debug/../src/main.cpp:31: undefined reference to `memory::Collector<core::Object*>::clean_up()'

It's like it can't see any of methods of Collector. Could it be due to my empty declaration of base non-specialized class Collector? But I tried to add there implementations of the methods and it did not help.

Upvotes: 1

Views: 52

Answers (1)

Paolo M
Paolo M

Reputation: 12757

Short answer

You can't put the definition (implementation) of function templates into a .cpp file. Put them into the same header where they are declared.

Explanation

This is because function templates get instantiated when (where) they are used, so the compiler needs to see how they are defined in any place they are used. There are some workarounds to take definition separate from declaration of function/class templates, but all of them imply the inclusion of the definition of the template into the translation unit in which it is used.

Upvotes: 3

Related Questions