在 C++11 中使用 CRTP 作为抽象静态方法的替代方法
Using CRTP as an alternative to abstract static methods in C++11
我正在尝试实现一个通用资源管理器,以确保每个资源仅使用 C++11 加载一次。
我的第一次尝试:
资源管理器.h
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include <map>
#include <memory>
template<typename T>
class ResourceManager {
public:
static std::shared_ptr<T> load(std::string filePath);
private:
static map<std::string, std::weak_ptr<T>> resources;
virtual static std::shared_ptr<T> loadResource(std::string filePath) = 0;
};
#endif // RESOURCEMANAGER_H
#include "resourcemanager.h"
资源管理器.cpp
using namespace std;
template<typename T>
map<string, weak_ptr<T>> ResourceManager<T>::resources;
template<typename T>
shared_ptr<T> ResourceManager<T>::load(std::string filePath) {
auto search = resources.find(filePath);
if (search != resources.end()) {
auto ptr = search->second.lock();
if (ptr) {
return ptr;
}
}
auto ptr = loadResource(filePath);
resources[filePath] = ptr;
return ptr;
}
然而,由于抽象静态方法显然是禁止的黑魔法,我尝试使用 CRTP:
资源管理器.h
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include <map>
#include <memory>
template<typename T, class Derived>
class ResourceManager {
public:
static std::shared_ptr<T> load(std::string filePath);
private:
static std::map<std::string, std::weak_ptr<T>> resources;
static std::shared_ptr<T> loadResource(std::string filePath);
};
#endif // RESOURCEMANAGER_H
资源管理器.cpp
#include "resourcemanager.h"
using namespace std;
template<typename T, class Derived>
map<string, weak_ptr<T>> ResourceManager<T, Derived>::resources;
template<typename T, class Derived>
shared_ptr<T> ResourceManager<T, Derived>::load(string filePath) {
auto search = resources.find(filePath);
if (search != resources.end()) {
auto ptr = search->second.lock();
if (ptr) {
return ptr;
}
}
auto ptr = ResourceManager::loadResource(filePath);
resources[filePath] = ptr;
return ptr;
}
template<typename T, class Derived>
shared_ptr<T> ResourceManager<T, Derived>::loadResource(string filePath) {
return Derived::loadResource(filePath);
}
这看起来应该做我想做的事。但是当我尝试使用它时,它在链接阶段失败:
managedstring.h
#ifndef MANAGEDSTRING_H
#define MANAGEDSTRING_H
#include "resourcemanager.h"
class ManagedString {
public:
ManagedString(std::string filePath);
std::string get();
private:
std::shared_ptr<std::string> ptr;
class StringManager : public ResourceManager<std::string, StringManager> {
private:
static std::shared_ptr<std::string> loadResource(std::string filePath);
};
};
#endif // MANAGEDSTRING_H
托管字符串.cpp
#include "managedstring.h"
using namespace std;
ManagedString::ManagedString(string filePath) {
ptr = StringManager::load(filePath);
}
string ManagedString::get() {
return *ptr;
}
shared_ptr<string> ManagedString::StringManager::loadResource(string filePath) {
// dummy implementation
return make_shared<string>("foo");
}
主.cpp
#include <iostream>
#include "managedstring.h"
using namespace std;
int main() {
ManagedString string1 = ManagedString("bar");
ManagedString string2 = ManagedString("foobar");
cout << string1.get() << endl;
cout << string2.get() << endl;
}
当我尝试使用 g++ -std=c++11 -o bin -Wall main.cpp managedstring.cpp resourcemanager.cpp
(使用 gcc 版本 5.3.0)编译它时,我收到以下错误消息:
/tmp/ccgqljOQ.o: In function `ManagedString::ManagedString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
managedstring.cpp:(.text+0xdd): undefined reference to `ResourceManager<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >,
ManagedString::StringManager>::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
这应该有效吗?这是编译器的缺点吗?还是我试图做一些我不应该做的事情。
我也考虑过改变我的设计,但我认为它并没有那么糟糕。随意不同意我的观点。
在 resourcemanager.h 中,这一行:
#include "resourcemanager.h"
应该是:
#include "resourcemanager.cpp"
这似乎只对您的第一个示例有效,但同样适用于所有其他示例。
否则,作为替代方法,将模板类的声明和定义放在同一个文件中。
相关文章:
- 尝试了解在导入的静态方法上使用删除方法时的错误
- 如何通过命名空间调用非静态方法
- 如何在没有实例的情况下获取非静态方法的类型?
- 调用从模板派生的类的静态方法,而不指定模板
- 如何在 c++ 中异步调用静态方法?
- C++ 将静态方法转换为简单方法
- 从另一个标头中的标头调用静态方法
- C++中静态方法的局部变量范围
- 如何启用使用另一个类的静态方法的模板函数的自动推导,从而消除冗长的调用方代码
- 使用本机 JNI 静态方法实现C++ Java 运行时错误
- 当只有静态方法受到影响时,如何解决C++中的链接器错误?
- 用c++中的纯虚拟方法抽象模板类
- 静态变量在同一个翻译单元中被静态方法使用时是否保证被初始化?
- 为什么链接器报告全局函数的乘法定义符号,而不是类静态方法
- 从部分专用模板方法调用模板非静态方法
- 如何使用 c++ 在 cocos2dx 中定义非静态方法
- C++使用*this从静态方法调用一个抽象方法
- 在 C++11 中使用 CRTP 作为抽象静态方法的替代方法
- 纯抽象类可以包含静态常量、静态方法或非虚析构函数吗?
- 抽象类和静态方法