提问人: 提问时间:6/28/2015 更新时间:6/28/2015 访问量:401
C++ SFML Gamedev Book - 来自 ResourceHolder 类的未解析外部符号
C++ SFML Gamedev Book - Unresolved External Symbol from ResourceHolder class
问:
我有以下三个文件,其中我找不到它产生的错误的来源:
Main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include "ResourceHolder.h"
namespace Textures
{
enum ID { Landscape, Airplane, Missile };
}
int main()
{
//...
try
{
ResourceHolder<sf::Texture, Textures::ID> textures;
textures.load(Textures::Airplane, "Airplane.png");
}
catch (std::runtime_error& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
//...
}
资源持有人.h
#pragma once
#include <map>
#include <string>
#include <memory>
#include <stdexcept>
#include <cassert>
template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
void load(Identifier id, const std::string& fileName);
Resource& get(Identifier id);
const Resource& get(Identifier id) const;
private:
void insertResource(Identifier id, std::unique_ptr<Resource> resource);
std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
};
资源持有人.cpp
#include "ResourceHolder.h"
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& fileName)
{
//Create and load resource
std::unique_ptr<Resource> resource(new Resource());
if (!resource->loadFromFile(fileName)) {
throw std::runtime_error("ResourceHolder::load - Failed to load " + fileName);
}
//If loading was successful, insert resource to map
insertResource(id, std::move(resource));
}
template <typename Resource, typename Identifier>
Resource& ResourceHolder<Resource, Identifier>::get(Identifier id)
{
auto found = mResourcemap.find(id);
assert(found != mResourceMap.end());
return *found->second();
}
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::insertResource(Identifier id, std::unique_ptr<Resource> resource)
{
//Insert and check success
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource)));
assert(inserted.second);
}
如果我要删除 main.cpp 中的 try-catch 组合,代码编译良好;但是,如果我把它留在那里,它会给我一个LNK2019(未解析的外部符号)错误。
此错误的根源是什么,我将如何修复它?
答:
0赞
aslg
6/28/2015
#1
不能在 .cpp 文件中定义模板。它们必须在标头中定义,以便编译器可以看到实现并生成特定的类。
这里有一个更好的问题/答案,说明为什么会这样:为什么模板只能在头文件中实现?。
编辑:get
函数中有什么问题
两件事。
首先是这个.您的地图名称不正确,应为大写的 -> 。auto found = mResourcemap.find(id);
m
mResourceMap
然后是.映射迭代器包含一对,第一个和第二个成员不是函数,而是数据成员。你应该写.return *found->second();
return *found->second;
我建议您在使用模板之前了解您正在使用的结构。模板的编译错误非常混乱且难以阅读。此外,您可以创建一个单独的测试程序,并制作一个没有模板的资源管理器,以便更轻松地理解您的错误,然后在您的工作资源管理器之上构建模板。
评论
0赞
6/28/2015
这很有趣。我将 CPP 中的代码放入 H 文件中,现在代码工作正常,但是我无法使用 get 函数为精灵等设置纹理。您知道使用“textures.get(Textures::Airplane)”之类的东西时可能导致编译错误的原因吗?
0赞
6/28/2015
谢谢。我像你说的那样改变了一切,现在它运行良好。
0赞
user2946316
6/28/2015
#2
所有其他答案都为您提供了足够的信息,说明为什么您的代码无法编译并且可能无效,这是我前段时间为 SFML 编写的资源管理器,可能对您有用:
HPP 文件:
#ifndef RESOURCEMANAGER_HPP
#define RESOURCEMANAGER_HPP
/************ INCLUDES ***********/
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
class ResourceManager
{
private:
std::map<std::string,std::unique_ptr<sf::Texture>> listImageContainer;
std::map<std::string,std::pair<std::unique_ptr<sf::SoundBuffer>,std::unique_ptr<sf::Sound>>> listSoundContainer;
std::map<std::string,std::unique_ptr<sf::Font>> listFontContainer;
public:
ResourceManager();
std::unique_ptr<sf::Sound>& LoadSound(const std::string);
std::unique_ptr<sf::Font>& LoadFont(const std::string);
std::unique_ptr<sf::Texture>& LoadImage(const std::string);
~ResourceManager();
};
#endif
CPP 文件:
#include "ResourceManager.hpp"
ResourceManager::ResourceManager()
{
}
std::unique_ptr<sf::Sound>& ResourceManager::LoadSound(const std::string _fileName)
{
if (listSoundContainer.find(_fileName) == listSoundContainer.end())
{
std::unique_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer());
if (soundBuffer->loadFromFile("assets/sound/" + _fileName) != false)
{
std::unique_ptr<sf::Sound> sound(new sf::Sound(*soundBuffer));
listSoundContainer[_fileName] = std::make_pair(std::move(soundBuffer), std::move(sound));
return listSoundContainer[_fileName].second;
}
else
{
std::cerr << "Error loading sound..." << std::endl;
}
}
else
{
return listSoundContainer[_fileName].second;
}
}
std::unique_ptr<sf::Font>& ResourceManager::LoadFont(const std::string _fileName)
{
if (listFontContainer.find(_fileName) == listFontContainer.end())
{
std::unique_ptr<sf::Font> font(new sf::Font());
if (font->loadFromFile("assets/font/" + _fileName)!=false)
{
listFontContainer[_fileName] = std::move(font);
return listFontContainer[_fileName];
}
else
{
std::cerr << "Error loading font..." << std::endl;
}
}
else
{
return listFontContainer[_fileName];
}
}
std::unique_ptr<sf::Texture>& ResourceManager::LoadImage(const std::string _fileName)
{
if (listImageContainer.find(_fileName) == listImageContainer.end())
{
std::unique_ptr<sf::Texture> texture(new sf::Texture);
if (texture->loadFromFile("assets/image/" + _fileName)!=false)
{
listImageContainer[_fileName] = std::move(texture);
return listImageContainer[_fileName];
}
else
{
std::cerr << "Error loading image: " << _fileName << std::endl;
}
}
else
{
return listImageContainer[_fileName];
}
}
ResourceManager::~ResourceManager(){}
如何使用:
ResourceManager resourceManager;
auto& sound = resourceManager.LoadSound("nice.wav");
auto& image = resourceManager.LoadImage("head.png");
auto& sound2 = resourceManager.LoadSound("nice.wav"); //<--- already loaded
sound.play();
etc...
评论