Search code examples
c++templatesnamespaceslinkerdefined

Linker errors for namespace being included multiple times


I'm trying to fix an "explicit specialization in non-namespace scope" error using the method described in this post. So I managed to move the templated functions into a separate namespace, and I'm calling these functions from my class (see the code below).

The code now compiles, however I'm getting linker errors " already defined in main.obj" for all the functions in the namespace. I thought that adding #ifndef STYLE_H at the top would prevent the namespace from being included multiple times or am I missing something? How can I fix this error?

Below is my code (simplified):

#ifndef STYLE_H
#define STYLE_H

namespace hanzi {

namespace styleUtil {

    template <class T> 
    T get(const QString& name, T defaultValue = T(), const Style* style = NULL, const Style* baseStyle = NULL) {    
        // ...
    }

    template <> 
    QColor get<QColor>(const QString& name, QColor defaultValue, const Style* style, const Style* baseStyle) {  
        // ...
    }

    template <> 
    ImagingEffect get<ImagingEffect>(const QString& name, ImagingEffect defaultValue, const Style* style, const Style* baseStyle) { 
        // ...
    }

}

class Style : public QObject {

    Q_OBJECT

public:

    explicit Style(const QString& filePath);

    template <class T> 
    T get(const QString& name, T defaultValue = T()) const {
        return styleUtil::get<T>(name, defaultValue, this, baseStyle_);
    };

};

}

#endif // STYLE_H

Solution

  • Regarding the original error,

    I'm trying to fix an "explicit specialization in non-namespace scope" error

    What that error means is that you cannot define member function template specializations inside a class definition. I.e. the following would be illegal:

    struct Bar
    {
        template <typename T> void boo() { }
        // template <> void boo<char>() { boo<int>(); }  // Error! Cannot specialize here
    };
    

    However, this is solved by simply placing the specialisation outside the class definition:

    template <> void Bar::boo<char>() { boo<int>(); }  // Good.
    

    (The latter position of the specialization is "at namespace scope", for example at global scope, which is what the error message wanted to tell you to do.)