在Objective-C++(.mm)文件中使用模板化类时使用未定义的符号



这是一个使用Xcode 13.2.1版本创建的Objective-C macOS项目。在项目内部,我有一个名为"的模板化类;plistModifier";。该类用于为任何plist(例如NSStringNSNumber等(设置自定义类型的值;plistModifier.h";它看起来像这样:

#ifndef plistModifier_h
#define plistModifier_h
#include <iostream>
#include <string>
#import <Foundation/Foundation.h>
#include <unistd.h>
template <class type>
class plistModifier {

public:
void modifyPref(std::string key, type value);
type getPref(std::string key);
};

#endif /* plistModifier_h */

该类的实现在单独的";plistModifier.mm";文件:

#include "plistModifier.h"
template <class type>
void plistModifier<type>::modifyPref(std::string key, type val) {

NSString* preferencePlist = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/com.rA9.LeetDownPreferences.plist"];
NSDictionary* dict=[[NSDictionary alloc] initWithContentsOfFile:preferencePlist];
[dict setValue:val forKey:[NSString stringWithUTF8String:val]];
[dict writeToFile:preferencePlist atomically:YES];

}
template <class type>
type plistModifier<type>::getPref(std::string key) {

NSString *preferencePlist = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/com.rA9.LeetDownPreferences.plist"];
NSDictionary *dict=[[NSDictionary alloc] initWithContentsOfFile:preferencePlist];
return dict[key];
}

问题是,当我创建一个plistModifier对象并调用它的方法时,编译器会抛出错误Undefined symbols for architecture x86_64: "plistModifier<int>::modifyPref(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int)", referenced from: -[SettingsVC debuggingToggle:] in SettingsVC.o

这就是我如何调用SettingsVC.mm文件中对象的方法:

#import "SettingsVC.h"
#include "plistModifier.h"
plistModifier<int> plistObject;
- (IBAction)debuggingToggle:(id)sender {

plistObject.modifyPref("DebugEnabled", _debugToggle.state);
}

我曾尝试在一个空的C++项目中使用相同的模板类,但它没有给我任何错误。你认为问题出在哪里?

无法拆分模板声明(.h(和定义(.mm/.cpp(。您必须将模板方法的实现保存在.h文件中。

参考本解释

https://isocpp.org/wiki/faq/templates#templates-defn与decl

但是,由于您的实现没有使用泛型类型type属性,您可以通过在.mm中按照id类型实现它,然后在.h文件中添加一个模板化包装来拆分它:

// .mm
void plistModifierImpl::modifyPref(std::string key, id val) {    
NSString *preferencePlist = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/com.rA9.LeetDownPreferences.plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:preferencePlist];
[dict setValue:val forKey:[NSString stringWithUTF8String:val]];
[dict writeToFile:preferencePlist atomically:YES];    
}
// .h
class plistModifierImpl; // define this in .mm
template <class type>
class plistModifier {
// private loosely-typed implementation
std::unique_ptr<plistModifierImpl> p_impl;
public:
// public strongly-typed wrapper
void modifyPref(std::string key, type value) {
p_impl->modifyPref(key, value);
}
...
}

只要type可以隐式转换为id,这就可以工作,NSString、NSNumber、NSDate、NSArray和NSDictionary也是如此。

如果您需要支持像int这样的基元类型,则需要使用调整后的实现来专门化模板。

最新更新