多次包含命名空间的链接器错误

Linker errors for namespace being included multiple times

本文关键字:链接 错误 命名空间 包含      更新时间:2023-10-16

我正在尝试使用本文中描述的方法修复"非命名空间范围中的显式专用化"错误。因此,我设法将模板化的函数移到一个单独的命名空间中,并从类中调用这些函数(请参阅下面的代码)。

代码现在正在编译,但是我得到了"已经在main.obj中定义"的命名空间中所有函数的链接器错误。我认为在顶部添加#ifndef STYLE_H会防止命名空间被多次包含,或者我遗漏了什么?如何修复此错误?

以下是我的代码(简化):

#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

关于原始错误,

我正在尝试修复一个"非命名空间范围中的显式专业化"错误

这个错误意味着不能在类定义中定义成员函数模板专门化。也就是说,以下行为是非法的:

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

然而,这可以通过简单地将专业化放在类定义之外来解决:

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

(专业化的后一个位置是"在名称空间范围内",例如在全局范围内,这是错误消息想要告诉您的操作。)

函数模板的完全专业化不再是模板:它是一个函数。

因此,当您在标头中定义它时,需要添加关键字inline

inline改变了C++的"一个定义规则"(ODR)的行为。从本质上讲,对于inline,必须在每个翻译单元中定义函数;s,并且这些定义必须有效地相等。两者都是通过将定义放在头文件中来实现的。

inline也作为关于优化的提示,但不能保证第二个含义。

还要注意,为了这个答案不会误导你,不存在函数模板的部分专业化。