(Objective-) C ++ Duplicate character by pattern specialization

Ok, I have been struggling with this strange mistake since yesterday, so I think it's time to ask the community ...

I am currently working in Objective-C ++, and I have a purely cool class declaration in the header file, for example:

#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 

This template class with basic matrix operations, however, I want to optimize some bottlenecks in the specialization of templates on T = float. I included the Matrix.cpp file as follows:

 #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 

The problem is this: If I set USE_NEON_UPSAMPLING2X = false and USE_NEON_THRESHOLD = true, everything works fine - the application is built and works like a charm. However, if I set USE_NEON_UPSAMPLING2X = true, the linker breaks with the following:

 duplicate symbol __ZNK6MatrixIfE10upsample2xEv in: /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Ao /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Bo duplicate symbol __ZNK6MatrixIfE10upsample2xEv in: /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Ao /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Co duplicate symbol __ZNK6MatrixIfE10upsample2xEv in: /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Ao /.../OCRDemo-eggnlcolcwqycjagwvwddpfwgzlb/Build/Intermediates/OCRDemo.build/Release-iphoneos/OCRDemo.build/Objects-normal/armv7/Do 

The funny thing is that both methods are used in these files, however, the linker only complains about upsample2x ... The only difference between them, from the syntactic point of view, is the number of arguments: the threshold has an argument from T, while upsample2x does not require any - in addition, both of them are defined as const, as return matrices, etc.

So my question is: what causes this cryptic error and how can I fix it?

+4
source share
2 answers

Your mistake is twofold. First of all, you write the template code in a .cpp file. Then, to fix this error, you include the .cpp file in the header, another bad idea.

Why?

The class template is not really a class, but just a template for a group of classes. Classes that can be made from it are created as needed. On the other hand, the .cpp file is compiled only once, which is insufficient and does not even make sense, because at the moment you only have a template.

On the other hand, including a .cpp file on its own is bad, since it usually leads to recompilation of code that cannot be recompiled, hence communication errors.

EDIT: either you can define specializations in the .cpp file (but not clean template code and not include it!), Or you can embed them and save them in the header:

 #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 } 
+9
source

Add inline to your definitions.

+4
source

Source: https://habr.com/ru/post/1499610/


All Articles