6

好吧,我从昨天开始就一直在为这个奇怪的错误而苦苦挣扎,所以我想是时候问问社区了……

我目前正在使用 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,都返回矩阵等。

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

4

2 回答 2

11

你的错误是双重的。首先,您在 .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
}
于 2013-08-29T12:37:40.627 回答
7

添加inline到您的定义中。

于 2013-08-29T14:36:13.213 回答