(目标 - )C ++模板专业化上的重复符号

时间:2013-08-29 12:13:36

标签: c++ xcode templates linker-errors objective-c++

好吧,自昨天以来,我一直在努力解决这个奇怪的错误,所以我想是时候向社区提问......

我目前正在使用Objective-C ++,我在头文件中有一个纯粹的C ++类声明,如下所示:

#ifndef __MATRIX_H__
#define __MATRIX_H__

#define USE_NEON_UPSAMPLING2X true
#define USE_NEON_THRESHOLD true

typedef float OCRfloat;

template<class T = OCRfloat>
class Matrix {

public:
    ...

    Matrix threshold(T thresholdValue) const;

    ...

    Matrix upsample2x() const;

    ...
};

#ifdef TARGET_OS_IPHONE

#if USE_NEON_UPSAMPLING2X
template<> Matrix<float> Matrix<float>::upsample2x() const;
#endif

#if USE_NEON_THRESHOLD
template<> Matrix<float> Matrix<float>::threshold(float thresholdValue) const;
#endif

#endif

#include "Matrix.cpp"

#endif

它是模板类,具有基本矩阵运算,但是,我想通过 T = float 上的模板特化来优化一些瓶颈。我有包含的Matrix.cpp文件,如下所示:

#include <iostream>
#include <cmath>

#if defined TARGET_OS_IPHONE
#include <Accelerate/Accelerate.h>
#endif

...

template<class T> Matrix<T> Matrix<T>::threshold(T thresholdValue) const {
   ... // general naive algorithm
}

template<class T> Matrix<T> Matrix<T>::upsample2x() const{
   ... // general naive algorithm
}

#ifdef TARGET_OS_IPHONE

#if USE_NEON_UPSAMPLING2X
template<> Matrix<float> Matrix<float>::upsample2x() const{
   ... // specialized for ARM NEON float32_t
}
#endif

#if USE_NEON_THRESHOLD
template<> Matrix<float> Matrix<float>::threshold(float thresholdValue)const{
   ... // specialized for ARM NEON float32_t
}
#endif

问题如下: 如果我定义USE_NEON_UPSAMPLING2X = false和USE_NEON_THRESHOLD = true,一切正常 - 应用程序已构建,并且像魅力一样工作。但是,如果我将USE_NEON_UPSAMPLING2X设置为true,则链接器会断开以下内容:

duplicate symbol __ZNK6MatrixIfE10upsample2xEv in:
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/A.o
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/B.o
duplicate symbol __ZNK6MatrixIfE10upsample2xEv in:
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/A.o
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/C.o
duplicate symbol __ZNK6MatrixIfE10upsample2xEv in:
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/A.o
    /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/D.o

有趣的是这两个方法都在这些文件中使用,但链接器只抱怨upsample2x ...两者之间的唯一区别,从语法的角度来看是参数的数量:阈值有一个参数T,而upsample2x不需要 - 除此之外,两者都被定义为const,两者都是返回矩阵等。

所以我的问题是:是什么导致这个神秘的错误,我该如何解决?

2 个答案:

答案 0 :(得分:9)

您的错误是双重的。首先,您在.cpp文件中编写模板代码。然后,为了纠正该错误,将.cpp文件包含在标题中,这是另一个坏主意。

为什么?

类模板实际上不是一个类,而只是一组类的模板。可以根据需要创建可以从中创建的类。另一方面,.cpp文件只编译一次,这是不够的,甚至没有意义,因为此时你只有一个模板。

另一方面,包含.cpp文件本身就是一件坏事,因为它通常会导致重新编译可能无法重新编译的代码,从而导致链接错误。

编辑:您可以在.cpp文件中定义特化(但没有纯模板代码,也不包括它!),或者您可以内联它们并将它们保留在标题中:

#if USE_NEON_UPSAMPLING2X
template<> inline Matrix<float> Matrix<float>::upsample2x() const{
   ... // specialized for ARM NEON float32_t
}
#endif

#if USE_NEON_THRESHOLD
template<> inline Matrix<float> Matrix<float>::threshold(float thresholdValue)const{
   ... // specialized for ARM NEON float32_t
}

答案 1 :(得分:4)

inline添加到您的定义中。