0

Hey there i am trying to implement a simple config value class with a global list which holds these values. My implementation looks like this:

template <typename Y>
class ConfigSetting;

template <typename T>
class Global {
public:
     static ConfigSetting<T>* head;
     static ConfigSetting<T>* tail;
};

template <typename T>
class ConfigSetting {
public:
    ConfigSetting(const std::string& name, const std::string& synopsis, T initValue) : m_name(name), m_synopsis(synopsis), m_value(initValue)
    {
        this->addToList();
    }

    static ConfigSetting* findSetting(const std::string& name)
    {
        if (Global<T>::head) {
            Global<T> temp = Global<T>::head;
            while (!temp) {
                if (temp->m_name == name) {
                    return Global<T>::head;
                }
                temp = temp->m_next;
            }
        }
        return nullptr;
    }

private:
    void addToList(void)
    {
        if (Global<T>::head) {
            Global<T>::tail->m_next = this;
            Global<T>::tail = this;
        }
        else {
            Global<T>::head = this;
            Global<T>::tail = this; 
        }
    }

    ConfigSetting* m_next;
    const std::string m_name;
    const std::string m_synopsis;
T m_value;
T m_min;
T m_max;

Now this compiles fine, but gives me 2 linker errors:

error LNK2001: unresolved external symbol "public: static class ConfigSetting<int> * Global<int>::head" (?head@?$Global@H@@2PAV?$ConfigSetting@H@@A)
error LNK2001: unresolved external symbol "public: static class ConfigSetting<int> * Global<int>::tail" (?tail@?$Global@H@@2PAV?$ConfigSetting@H@@A)

I believe that this has something to do with the kind of circular dependency i created at the top. How can i solve this, or is there a better way doing this with templates? I did not want to create one class for each type i want to support.

puelo
  • 5,464
  • 2
  • 34
  • 62
  • 3
    Do you know how to use `static` variables in class ? – P0W Mar 23 '14 at 18:43
  • In the `findSetting` function. are you sure you want to return the head of the list when the node you found is `temp`? Also, why use your own list instead of a [standard container](http://en.cppreference.com/w/cpp/container)? In this case, a [`std::unordered_map`](http://en.cppreference.com/w/cpp/container/unordered_map) would be perfect. – Some programmer dude Mar 23 '14 at 18:46
  • Yes you were right about what i wanted to return. @P0W: I know that this is thought as a hint, but i sincerely don't see what i am doing wrong...i know how to use static variables. – puelo Mar 23 '14 at 18:49

2 Answers2

1

A linker errors are always the same error: your linker doesn't have the code. Once you understand that, you will solve linker error much easily :) in this case, the missing code is the defeintion of the static variables. in your class you Declare them, but you didn't Defined them. Here is the syntax of how to define static variable of a Class Template: Using static variable along with templates

I think you got a little messed up with the template classes here (they are a tough part of c++, so don't fill bad about it :)

I think this is what you tried to do:

#include "stdafx.h"
#include <string>
using namespace std;

template <typename T>
class ConfigSetting {
public:
    static ConfigSetting* head; // I fixed here, no need for Global, you have this class static vars
    static ConfigSetting* tail;
public:
    ConfigSetting(const std::string& name, const std::string& synopsis, T initValue) : m_name(name), m_synopsis(synopsis), m_value(initValue)
    {
        this->addToList();
    }

    static ConfigSetting* findSetting(const std::string& name)
    {
        if (head) {
            ConfigSetting* temp = head;
            while (!temp) {
                if (temp->m_name == name) {
                    return temp; // I fixed here, you have to return the object you find
                }
                temp = temp->m_next;
            }
        }
        return nullptr;
    }

private:
    void addToList() // no need for 'void' this is C++, not C
    {
        if (head) {
            tail->m_next = this;
            tail = this;
        }
        else {
            head = this;
            tail = this; 
        }
    }

    ConfigSetting* m_next;
    const std::string m_name;
    const std::string m_synopsis;
    T m_value;
    T m_min;
    T m_max;
};

template <typename T>
ConfigSetting<T>* ConfigSetting<T>::head = nullptr;

template <typename T>
ConfigSetting<T>* ConfigSetting<T>::tail = nullptr;

int _tmain(int argc, _TCHAR* argv[])
{
    ConfigSetting<int> j("name", "syn", 1);
    return 0;
}
Community
  • 1
  • 1
ShaulF
  • 841
  • 10
  • 17
1

Define (outside the class) the static head and tail pointers as

   template<typename T>
    ConfigSetting<T>*  Global<T>::tail = nullptr ;
   template<typename T>
    ConfigSetting<T>*  Global<T>::head = nullptr ;
P0W
  • 46,614
  • 9
  • 72
  • 119